[python] Getters and Setters.
Filip Štědronský
regnarg na seznam.cz
Sobota Červen 21 20:13:21 CEST 2008
On So, čen 21, 2008 at 07:20:22 +0200, David Michal wrote:
> Ta promena x je pak promenou tridy, nebo instance? Co se stane kdyz
> upravim __init__ takto:
> def __init__(self):
> self.x = 0
> self.x = property(self.get_x, self.set_x)
Property je určena k tomu, aby byla uložena v proměnné
třídy, i když slouží jako proměnná instance. Efekty v
jiném případě by mohly být nepředvídatelné. Chování
property() bylo takhle navrženo naschvál, aby připomínalo
něco jako "deklaraci" v rámci definice třídy. Ale samotná
vlastnost reprezentuje hodnotu vztahující se k instanci.
Vzhledem ke složité sémantice ohledně parametru self si
nejsem jist, zda by bylo property možno použít jinak, než
jak bylo zamýšleno, protože parametry funkce property()
předávané v těle třídy jsou ještě holé funkce,
očekávající explicitní parametr self a ne "magické"
metody instance.
Property vytváří tzv. deskriptor, tedy objekt s metodami
__get__, __set__, etc. Tyto metody teprve dostanou jako
parametr aktuální instanci (automaticky, když Python
zjistí, že jde o deskriptor) a zavolají holou funkci s
parametrem této instance, případně u setteru nové
hodnoty. Pro funkci samotnou je to nerozeznatelné od
použití jako instanční metody: self dostane, parametry
dostane, tak si nemá co stěžovat.
Z uvedeného jasně vyplývá, že se nemusíme omezovat na
property. Můžeme si napsat vlastní deskriptory, stačí,
aby implementovali __get__, příp. __set__. Já osobně
doporučuji můj deskriptor prop(), který neuchovává odkaz
na funkci, ale její název, takže může být předefinována
v podtřídě, aniž by se musela předefinovat vlastnost
samotná.
Kód přikládám také pro představu, jak deskriptory vlastně
vypadají. Parametry __get__ jsou instance (None při použití
jako proměnná třídy) a třída objektu, jehož atributem
deskriptor je. U ostatních netřeba vysvětlovat. Magické
chování deskriptorů funguje jen v rámci objektů, tzn. v
obyčejné proměnné uvidíme vždy deskriptor samotný.
class prop(object):
"""A replacement of `property' that work correctly with subclasses
and manages that by name-based remembering of accessor methods (aka
getters and setters) in contrast to property's method object storing.
If the accessors are redefined in a subclass, the prop object can be
left intact, whereas a property requires to be redefined each time an
accessor is overriden."""
def __init__(self,fget=None,fset=None,fdel=None):
if fget is None:
self.fget=None
else:
self.fget=fget.__name__
if fset is None:
self.fset=None
else:
self.fset=fset.__name__
if fdel is None:
self.fdel=None
else:
self.fdel=fdel.__name__
def __get__(self,i,o):
if self.fget is None: return
if i is None:
return getattr(o,self.fget)()
else:
return getattr(i,self.fget)()
def __set__(self,i,v):
if self.fset is None: return
getattr(i,self.fset)(v)
def __delete__(self,i):
if self.fdel is None: return
getattr(i,self.fdel)()
Pokud definujeme:
class A(object):
def myget(self):
return 0
a=property(myget)
b=prop(myget)
class B(A):
def myget(self):
return 1
Dostáváme:
>>> b=B()
>>> b.a
0
>>> b.b
1
Doufám, že jsem to vysvětlil dost jasně a neudělal moc
chyb (případně nechť mě opraví jiní).
Přeji hezký zbytek večera,
regnarg
--
regnarg --- http://rg.pretel.cz -- JID: regnarg na jabber.cz
V péči o štěstí druhých nacházíme své vlastní. --Platón
Přátelství může trvat jedině mezi dobrými lidmi. --Cicero
Další informace o konferenci Python