Как сделать дефолт безопасным для ничего не подозревающих клиентов? - PullRequest
6 голосов
/ 13 июня 2010

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

d = defaultdict(list)

...

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

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

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

Ответы [ 5 ]

14 голосов
/ 13 июня 2010

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

d = collections.defaultdict(list)
d = dict(d)
7 голосов
/ 13 июня 2010

используйте другую идиому:

if 'key' not in d:
    print "Sorry, no dice!"
5 голосов
/ 13 июня 2010

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

2 голосов
/ 13 июня 2010

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

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

1 голос
/ 13 июня 2010

Используя идею Рхайрова о сбросе 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]})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...