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.