Záludnosti property v Pythonu
Property je velmi užitečná a hojně používáná vlastnost jazyka Python. Přináší ale i jistá úskalí, o kterých je dobré vědět.
Property umožňují skrýt logiku získání dat a navenek se tvářit jako obyčejný atribut. Další možností použití je omezení/validace zapisovaných dat.
Můžeme se ale díky nim setkat i s velmi podivných chováním, které nám může pořádně zesložitit debugování.
Skrytá immutabilita
Mějme například tento kód:
x.errors['a'] = 1 print(type(x.errors)) print(x.errors)
Typ atributu errors je dict. Každý by tedy asi očekával, že obsahem bude nakonec nějaký díct, obsahující i klíč "a".
Ejhle, není to tak. Můžeme do x.errors zapisovat jak chceme, ale bude nám stále vracet původní hodnotu. Je to totiž property:
@property def errors(self): return {}
Takováto změna z běžného atributu "errors" na property nastala v knihovně WTForms a dohledat jí byl opravdu oříšek.
Konflikt mezi property a __getattr__
Pojďme na druhou ukázku:
class UserProxy: user = None data = {} def __getattr__(self, name): return self.data[name] @property def is_admin(self): return self.user.has_root_role user = UserProxy() user.is_admin
Výsledkem je chyba:
Traceback (most recent call last): File "test.py", line 15, inuser.is_admin File "test.py", line 7, in __getattr__ return self.data[name] KeyError: 'is_admin'
Což není moc očekávané. Přistupovali jsme přeci na property "is_admin", o které víme, že tam je a najednou nám padne nějaký KeyError úplně odjinud.
Problém je v tom, že jakmile kdekoliv v těle property vylítne AttributeError výjimka, bere se to tak, že se nepovedlo původní atribut vůbec najít, a hledá se dál pomocí "__getattr__".
S property v Pythonu je tedy potřeba zacházet s opatrností a důkladně rozmýšlet, co jejich použitím získáme a co naopak mohou přinést za problémy.