[Python] Abstrakcyjne właściwości w pythonie

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!

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Log Out / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Log Out / Zmień )

Facebook photo

Komentujesz korzystając z konta Facebook. Log Out / Zmień )

Google+ photo

Komentujesz korzystając z konta Google+. Log Out / Zmień )

Connecting to %s