https://docs.python.org/3/library/functions.html#property
Typowe zastosowanie dekoratora @property to utworzenie zarządzalnego atrybutu. Użytkownik używa składni takiej samej jak dla zwykłego atrybutu (odczyt, podstawienie), a jednocześnie w niewidoczny sposób mogą być wykonywane inne operacje.
class C(object): """Klasa C.""" def __init__(self): self.x = None c = C() # dir(c) # widać 'x' c.x = 20 print(c.__doc__) # Klasa C. print(c.x) # 20 del c.x print(c.x) # AttributeError: 'C' object has no attribute 'x'
class C(object): """Klasa C.""" def __init__(self): self._x = None self.threshold = 10 def getx(self): # getting an attribute value # instrukcje ... return self._x def setx(self, value): # setting an attribute value # instrukcje ... if value < self.threshold: raise ValueError("x can't be lesser than {}".format(self.threshold)) else: self._x = value def delx(self): # deleting an attribute value # instrukcje ... del self._x # chyba lepiej self._x = None (?) x = property(getx, setx, delx, "I'm the 'x' property.") c = C() # dir(c) # widać 'x' i '_x' c.x = 20 # działa setx, to samo co c.setx(20) #c.x = 5 # ValueError: x can't be lesser than 10 print(c.__doc__) # Klasa C. # W trybie interaktywnym help(c) lub help(C) ujawnia dla x string "I'm the 'x' property." print(c.x) # działa getx, to samo co dla c.getx() del c.x # działa delx, to samo co c.delx() print(c.x) # AttributeError: 'C' object has no attribute '_x'
# Od Py2.6 można użyć metod obiektu property: getter, setter, deleter. # Trzeba użyć tej samej nazwy (tu x i _x). # Tu jest użycie property jako dekoratora. class C(object): """Klasa C.""" def __init__(self): self._x = None self.threshold = 10 @property def x(self): # getting an attribute value """I'm the 'x' property.""" # instrukcje ... return self._x @x.setter def x(self, value): # setting an attribute value # instrukcje ... if value < self.threshold: raise ValueError("x can't be lesser than {}".format(self.threshold)) else: self._x = value @x.deleter def x(self): # deleting an attribute value # instrukcje ... del self._x # chyba lepiej self._x = None (?) c = C() # dir(c) # widać 'x' i '_x' c.x = 20 print(c.x) # 20 #c.x = 5 # ValueError: x can't be lesser than 10 del c.x
# Składnia dekoratorów klas ma następującą postać. @decorator2 @decorator1 class C(object): pass # ... co jest równoważne ... class C(object): pass C = decorator2(decorator1(C))
# Dekorator klasy. def class_decorator(cls): pass @class_decorator # zastosowanie class C(object): pass # lub inaczej class C(object): pass C = class_decorator(C)
# https://stackoverflow.com/questions/392160/what-are-some-concrete-use-cases-for-metaclasses # Zastosowanie dekoratora klasy do rejestracji klas. models = {} def model(cls): models[cls.__name__] = cls return cls @model class A(object): pass class B(A): pass # Klasa B nie będzie rejestrowana, chyba że jawnie użyjemy znowu @model. # Lepsze rozwiązanie wykorzystuje metaklasy.
models = {} class ModelMetaclass(type): def __new__(meta, name, bases, clsdict): models[name] = cls = type.__new__(meta, name, bases, clsdict) return cls #class Model(object): # __metaclass__ = ModelMetaclass # Py2 class Model(metaclass=ModelMetaclass): # Py3 pass class A(Model): pass class B(A): # teraz klasa B będzie zarejestrowana w models pass print(list(models)) # ['A', 'Model', 'B']