property to jedna z wbudowanych funkcji pythona (od wersji 2.2.). Zwraca ona obiekt implementujący protokół deskryptorów
class Shape(object):
def __init__(self):
pass
def get_area(self):
pass
Area = property(fget = get_area)
class Rect(Shape):
def __init__(self,w,h):
self.width, self.height = w,h
def get_area(self):
return self.width * self.height
class Circle(Shape):
def __init__(self):
self.radius = r
def get_area(self):
return math.pi * self.r**2;
s = Rect(20,10)
print r.Area
s = Circle(2);
print s.Area
Niestety, ten kod nie zadziała zgodnie z oczekiwaniami. Właściwości nie są abstrakcyjne. To, czego potrzebujemy ( przynajmniej ja ) znajduje się tutaj An Overrideable Alternative to the property Function in Python .
class OProperty(object):
"""Based on the emulation of PyProperty_Type() in Objects/descrobject.c"""
def __init__(self, fget=None, fset=None, fdel=None, doc=None):
self.fget = fget
self.fset = fset
self.fdel = fdel
self.__doc__ = doc
def __get__(self, obj, objtype=None):
if obj is None:
return self
if self.fget is None:
raise AttributeError, "unreadable attribute"
if self.fget.__name__ == '<lambda>' or not self.fget.__name__:
return self.fget(obj)
else:
return getattr(obj, self.fget.__name__)()
def __set__(self, obj, value):
if self.fset is None:
raise AttributeError, "can't set attribute"
if self.fset.__name__ == '<lambda>' or not self.fset.__name__:
self.fset(obj, value)
else:
getattr(obj, self.fset.__name__)(value)
def __delete__(self, obj):
if self.fdel is None:
raise AttributeError, "can't delete attribute"
if self.fdel.__name__ == '<lambda>' or not self.fdel.__name__:
self.fdel(obj)
else:
getattr(obj, self.fdel.__name__)()
I wówczas
class Shape(object):
def __init__(self):pass
def get_area(self): pass
Area = OProperty(fget = get_area, doc='Calculate area of shape')
class Rect(Shape):
def __init__(self,w,h):
self.width, self.height = w,h
def get_area(self):
return self.width * self.height
class Circle(Shape):
def __init__(self,r):
self.radius = r
def get_area(self):
return math.pi * self.radius**2
s = Rect(w=10,h=10);print s.Area;
s = Circle(r=1); print s.Area;
Voila!