Debuguję kod i chcę się dowiedzieć, kiedy uzyskuje się dostęp do określonego słownika. Cóż, w rzeczywistości jest to klasa, która jest podklasą dict
i implementuje kilka dodatkowych funkcji. W każdym razie chciałbym zrobić podklasę dict
siebie i dodać nadpisanie __getitem__
oraz __setitem__
wygenerować wyjście debugowania. Teraz mam
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'
jest kluczem, który ostatecznie zostanie ustawiony i którego chcę użyć do zidentyfikowania wyniku. Następnie zmieniłem klasę, którą obsługuję, na podklasę DictWatch
zamiast dict
i zmieniłem wywołanie superkonstruktora. Mimo wszystko wydaje się, że nic się nie dzieje. Myślałem, że jestem sprytny, ale zastanawiam się, czy powinienem iść w innym kierunku.
Dzięki za pomoc!
python
dictionary
Michael Mior
źródło
źródło
dict.__init__
bierze*args
?Odpowiedzi:
To, co robisz, powinno absolutnie działać. Przetestowałem twoją klasę i poza brakującym nawiasem otwierającym w twoich instrukcjach dziennika, działa dobrze. Przychodzą mi do głowy tylko dwie rzeczy. Po pierwsze, czy dane wyjściowe instrukcji log są ustawione poprawnie? Może być konieczne umieszczenie
logging.basicConfig(level=logging.DEBUG)
u góry skryptu.Po drugie,
__getitem__
i__setitem__
są wywoływane tylko podczas[]
dostępu. Upewnij się więc, że masz dostęp tylkoDictWatch
przezd[key]
, a nied.get()
id.set()
źródło
(str(dict.get(self, 'name_label')), str(key), str(val)))
Innym problemem podczas tworzenia podklas
dict
jest to, że element wbudowany__init__
nie wywołujeupdate
, a element wbudowanyupdate
nie wywołuje__setitem__
. Tak więc, jeśli chcesz, aby wszystkie operacje setitem przechodziły przez twoją__setitem__
funkcję, powinieneś upewnić się, że zostanie wywołana samodzielnie: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
źródło
print
był toprint()
funkcja, aupdate()
metoda używaitems()
zamiastiteritems()
.__getitem__
musiałby przetestowaćval
i zrobić to tylko warunkowo - tj.if isinstance(val, dict): ...
Rozważ podklasy
UserDict
lubUserList
. Te klasy są przeznaczone do podklasy, podczas gdy normalnedict
ilist
nie są, i zawierają optymalizacje.źródło
To nie powinno tak naprawdę zmienić wyniku (co powinno działać, dla dobrych wartości progowych logowania): twój init powinien być:
def __init__(self,*args,**kwargs) : dict.__init__(self,*args,**kwargs)
zamiast tego, ponieważ wywołanie metody z DictWatch ([(1,2), (2,3)]) lub DictWatch (a = 1, b = 2) zakończy się niepowodzeniem.
(lub lepiej nie definiuj konstruktora)
źródło
dict[key]
formę dostępu, więc to nie jest problem.Wszystko, co będziesz musiał zrobić, to
class BatchCollection(dict): def __init__(self, inpt={}): super(BatchCollection, self).__init__(inpt)
Przykładowe użycie do użytku osobistego
### 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")
Uwaga : testowano tylko w python3
źródło
Aby uzupełnić odpowiedź na pasztet irlandzki, oto przykład pokazujący różnicę między
dict
aUserDict
:Trudno jest poprawnie nadpisać dyktando:
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
dziedziczą zcollections.abc.MutableMapping
, więc jest znacznie łatwiejsza do dostosowania: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}
Podobnie, trzeba tylko wdrożyć
__getitem__
automatycznie być zgodny zkey in my_dict
,my_dict.get
...Uwaga:
UserDict
nie jest podklasądict
, więcisinstance(UserDict(), dict)
zawiedzie (aleisinstance(UserDict(), collections.abc.MutableMapping)
będzie działać)źródło