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, in 
    user.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.

evaluation

comments

add comment