1. 程式人生 > >python中Properties的一些小用法

python中Properties的一些小用法

class format height 屬性 orm 一個 one def cor

property最大的用處就是可以為一個屬性制定getter,setter,delete和doc,他的函數原型為:

    def __init__(self, fget=None, fset=None, fdel=None, doc=None): # known special case of property.__init__
        """
        property(fget=None, fset=None, fdel=None, doc=None) -> property attribute
        
        fget is a function to be used for getting an attribute value, and likewise
fset is a function for setting, and fdel a function for del‘ing, an attribute. Typical use is to define a managed attribute x: class C(object): def getx(self): return self._x def setx(self, value): self._x = value def delx(self): del self._x
x = property(getx, setx, delx, "I‘m the ‘x‘ property.") Decorators make defining new properties or modifying existing ones easy: class C(object): @property def x(self): "I am the ‘x‘ property." return self._x
@x.setter def x(self, value): self._x = value @x.deleter def x(self): del self._x # (copied from class doc) """ pass

從上邊的代碼中可以看出來,它一共接受4個參數,我們再繼續看一段代碼:

class Rectangle(object):
    def __init__(self, x1, y1, x2, y2):
        self.x1, self.y1 = x1, y1
        self.x2, self.y2 = x2, y2

    def _width_get(self):
        return self.x2 - self.x1

    def _width_set(self, value):
        self.x2 = self.x1 + value

    def _height_get(self):
        return self.y2 - self.y1

    def _height_set(self, value):
        self.y2 = self.y1 + value

    width = property(_width_get, _width_set, doc="rectangle width measured from left")
    height = property(_height_get, _height_set, doc="rectangle height measured from top")

    def __repr__(self):
        return "{}({}, {}, {}, {})".format(self.__class__.__name__,
                                           self.x1,
                                           self.y1,
                                           self.x2,
                                           self.y2)


rectangle = Rectangle(10, 10, 30, 15)
print(rectangle.width, rectangle.height)
rectangle.width = 50
print(rectangle)
rectangle.height = 50
print(rectangle)
print(help(rectangle))

通過property,我們有能力創造出一個屬性來,然後為這個屬性指定一些方法,在這裏用setter,getter的好處就是可以監聽屬性的賦值和獲取行為,表面上看上去上邊的代碼沒有問題,但是當出現繼承關系的時候,就出問題了。

class MetricRectangle(Rectangle):
    def _width_get(self):
        return "{} metric".format(self.x2 - self.x1)


mr = MetricRectangle(10, 10, 100, 100)
print(mr.width)

即使我們在子類中重寫了getter方法,結果卻是無效的,這說明property只對當前的類生效,於是不得不把代碼改成下邊這樣:

class MetricRectangle(Rectangle):
    def _width_get(self):
        return "{} metric".format(self.x2 - self.x1)

    width = property(_width_get, Rectangle.width.fset)


mr = MetricRectangle(10, 10, 100, 100)
print(mr.width)

因此,在平時的編程中,如果需要重寫屬性的話,應該重寫該類中所有的property,否則程序很很難以理解,試想一下,setter在子類,getter在父類,多麽恐怖

另一種比較好的方案是使用裝飾器,可讀性也比較好

class Rectangle(object):
    def __init__(self, x1, y1, x2, y2):
        self.x1, self.y1 = x1, y1
        self.x2, self.y2 = x2, y2

    @property
    def width(self):
        """rectangle width measured from left"""
        return self.x2 - self.x1

    @width.setter
    def width(self, value):
        self.x2 = self.x1 + value

    @property
    def height(self):
        return self.y2 - self.y1

    @height.setter
    def height(self, value):
        self.y2 = self.y1 + value

    def __repr__(self):
        return "{}({}, {}, {}, {})".format(self.__class__.__name__,
                                           self.x1,
                                           self.y1,
                                           self.x2,
                                           self.y2)


rectangle = Rectangle(10, 10, 30, 15)
print(rectangle.width, rectangle.height)
rectangle.width = 50
print(rectangle)
rectangle.height = 50
print(rectangle)
print(help(rectangle))

python中Properties的一些小用法