Как я делаю defaultdict сейф для неожидания клиентов?

Несколько раз (даже несколько подряд) я был укушен defaultdict ошибкой: упущение, что что-то - на самом деле defaultdict и обработка ее как регулярный словарь.

d = defaultdict(list)

...

try:
  v = d["key"]
except KeyError:
  print "Sorry, no dice!"

Для тех, кто был укушен также, проблема очевидна: когда d не имеет никакого ключевого 'ключа', v = d["key"] волшебно создает пустой список и присваивает его обоим d["key"] и v вместо того, чтобы повысить исключение. Который может быть настоящей болью, чтобы разыскать, если d прибывает из некоторого модуля, детали которого каждый не помнит очень хорошо.

Я ищу способ снизить остроту этой ошибки. Для меня лучшее решение состояло бы в том, чтобы так или иначе отключить волшебство defaultdict прежде, чем возвратить его клиенту.

6
задан JasonMArcher 23 May 2015 в 21:07
поделиться

5 ответов

Вы можете предотвратить создание значений по умолчанию, назначив d.default_factory = None . Однако мне не очень нравится идея о внезапном изменении поведения объекта. Я бы предпочел копировать значения в новый dict , если это не налагает серьезного снижения производительности.

5
ответ дан 8 December 2019 в 03:26
поделиться

использовать другую идиому:

if 'key' not in d:
    print "Sorry, no dice!"
7
ответ дан 8 December 2019 в 03:26
поделиться

Это именно то поведение, которое вы хотите от defaultdict , а не от ошибки . Если вам это не нужно, не используйте defaultdict.

Если вы все время забываете, какой тип имеют переменные, то назовите их соответствующим образом - например, суффикс ваших имен defaultdict с "_ddict".

2
ответ дан 8 December 2019 в 03:26
поделиться

Используя идею rkhayrov о сбросе self.default_factory, вот переключаемый подкласс defaultdict:

class ToggleableDefaultdict(collections.defaultdict):
    def __init__(self,default_factory):
        self._default_factory=default_factory
        super(ToggleableDefaultdict,self).__init__(default_factory)
    def off(self):
        self.default_factory=None
    def on(self):
        self.default_factory=self._default_factory

Например:

d=ToggleableDefaultdict(list)
d['key'].append(1)
print(d)
# defaultdict(<type 'list'>, {'key': [1]})

d.off()
d['newkey'].append(2)
# KeyError: 'newkey'

d.on()
d['newkey'].append(2)
# defaultdict(<type 'list'>, {'newkey': [2], 'key': [1]})
1
ответ дан 8 December 2019 в 03:26
поделиться

Вы все еще можете преобразовать его в обычный dict.

d = collections.defaultdict(list)
d = dict(d)
14
ответ дан 8 December 2019 в 03:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: