Я отлаживаю некоторый код и хочу узнать, когда осуществляется доступ к определенному словарю. Ну, на самом деле это класс, который является подклассом dict
и реализует пару дополнительных функций. В любом случае, я хотел бы создать подкласс dict
себя, добавить переопределение __getitem__
и __setitem__
произвести некоторый отладочный вывод. Прямо сейчас у меня есть
class DictWatch(dict):
def __init__(self, *args):
dict.__init__(self, args)
def __getitem__(self, key):
val = dict.__getitem__(self, key)
log.info("GET %s['%s'] = %s" % str(dict.get(self, 'name_label')), str(key), str(val)))
return val
def __setitem__(self, key, val):
log.info("SET %s['%s'] = %s" % str(dict.get(self, 'name_label')), str(key), str(val)))
dict.__setitem__(self, key, val)
' name_label'
- это ключ, который в конечном итоге будет установлен, и я хочу использовать его для идентификации вывода. Затем я изменил класс, который я использую для DictWatch
создания подкласса, dict
и изменил вызов суперконструктора. Тем не менее, похоже, что ничего не происходит. Я думал, что поступаю умно, но мне интересно, стоит ли мне идти в другом направлении.
Спасибо за помощь!
python
dictionary
Майкл Майор
источник
источник
dict.__init__
берет*args
?Ответы:
То, что вы делаете, должно работать. Я протестировал ваш класс, и, за исключением отсутствующей открывающей скобки в ваших операторах журнала, он отлично работает. Я могу думать только о двух вещах. Во-первых, правильно ли настроен вывод вашего журнала? Возможно, вам потребуется поставить
logging.basicConfig(level=logging.DEBUG)
в начало скрипта.Во- вторых,
__getitem__
и__setitem__
вызываются только во время[]
заходов. Поэтому убедитесь , что доступ толькоDictWatch
черезd[key]
, а неd.get()
иd.set()
источник
(str(dict.get(self, 'name_label')), str(key), str(val)))
Другая проблема при
dict
создании подклассов заключается в том, что встроенный__init__
не вызываетupdate
, а встроенныйupdate
не вызывает__setitem__
. Итак, если вы хотите, чтобы все операции setitem выполнялись через вашу__setitem__
функцию, вы должны убедиться, что она вызывается самостоятельно:class DictWatch(dict): def __init__(self, *args, **kwargs): self.update(*args, **kwargs) def __getitem__(self, key): val = dict.__getitem__(self, key) print('GET', key) return val def __setitem__(self, key, val): print('SET', key, val) dict.__setitem__(self, key, val) def __repr__(self): dictrepr = dict.__repr__(self) return '%s(%s)' % (type(self).__name__, dictrepr) def update(self, *args, **kwargs): print('update', args, kwargs) for k, v in dict(*args, **kwargs).iteritems(): self[k] = v
источник
print
этоprint()
функция иupdate()
метод используетitems()
вместоiteritems()
.__getitem__
нужно будет протестироватьval
и сделать это только при определенных условиях - то естьif isinstance(val, dict): ...
Рассмотрим создание подкласса
UserDict
илиUserList
. Эти классы предназначены для создания подклассов, тогда как обычныеdict
иlist
нет, и содержат оптимизацию.источник
Это на самом деле не должно изменить результат (который должен работать при хороших пороговых значениях регистрации): ваш init должен быть:
def __init__(self,*args,**kwargs) : dict.__init__(self,*args,**kwargs)
вместо этого, потому что если вы вызовете свой метод с помощью DictWatch ([(1,2), (2,3)]) или DictWatch (a = 1, b = 2), это не удастся.
(или, лучше, не определяйте для этого конструктор)
источник
dict[key]
форма доступа, так что это не проблема.Все, что вам нужно сделать, это
class BatchCollection(dict): def __init__(self, inpt={}): super(BatchCollection, self).__init__(inpt)
Пример использования для личного пользования
### EXAMPLE class BatchCollection(dict): def __init__(self, inpt={}): super(BatchCollection, self).__init__(inpt) def __setitem__(self, key, item): if (isinstance(key, tuple) and len(key) == 2 and isinstance(item, collections.Iterable)): # self.__dict__[key] = item super(BatchCollection, self).__setitem__(key, item) else: raise Exception( "Valid key should be a tuple (database_name, table_name) " "and value should be iterable")
Примечание : проверено только на python3
источник
Чтобы завершить ответ Эндрю Пэйта, вот пример, показывающий разницу между
dict
иUserDict
:Правильно перезаписать dict сложно:
class MyDict(dict): def __setitem__(self, key, value): super().__setitem__(key, value * 10) d = MyDict(a=1, b=2) # Bad! MyDict.__setitem__ not called d.update(c=3) # Bad! MyDict.__setitem__ not called d['d'] = 4 # Good! print(d) # {'a': 1, 'b': 2, 'c': 3, 'd': 40}
UserDict
наследовать отcollections.abc.MutableMapping
, поэтому настроить его намного проще:class MyDict(collections.UserDict): def __setitem__(self, key, value): super().__setitem__(key, value * 10) d = MyDict(a=1, b=2) # Good: MyDict.__setitem__ correctly called d.update(c=3) # Good: MyDict.__setitem__ correctly called d['d'] = 4 # Good print(d) # {'a': 10, 'b': 20, 'c': 30, 'd': 40}
Кроме того , вы должны реализовать только
__getitem__
автоматически быть совместимы сkey in my_dict
,my_dict.get
...Примечание:
UserDict
не является подклассомdict
, поэтомуisinstance(UserDict(), dict)
не удастся (ноisinstance(UserDict(), collections.abc.MutableMapping)
будет работать)источник