1. 程式人生 > >python基礎===裝飾器@property

python基礎===裝飾器@property

nts obj @property sar ttr 16px respond cto man

以下來自Python 3.6.0 Document:
class property(fget=None, fset=None, fdel=None, doc=None)

Return a property attribute.

fget is a function for getting an attribute value. fset is a function for setting an attribute value. fdel is a function for deleting an attribute value. And doc creates a docstring for the attribute.

A typical use is to define a managed attribute x:

class C:
    def __init__(self):
        self._x = None

    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.
")

If c is an instance of C, c.x will invoke the getter, c.x = value will invoke the setter and del c.x the deleter.

If given, doc will be the docstring of the property attribute. Otherwise, the property will copy fget‘s docstring (if it exists). This makes it possible to create read-only properties easily using property()

as a decorator:

class Parrot:
    def __init__(self):
        self._voltage = 100000

    @property
    def voltage(self):
        """Get the current voltage."""
        return self._voltage

The @property decorator turns the voltage() method into a “getter” for a read-only attribute with the same name, and it sets the docstring for voltage to “Get the current voltage.”

A property object has getter, setter, and deleter methods usable as decorators that create a copy of the property with the corresponding accessor function set to the decorated function. This is best explained with an example:

class C:
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I‘m the ‘x‘ property."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

This code is exactly equivalent to the first example. Be sure to give the additional functions the same name as the original property (x in this case.)

The returned property object also has the attributes fget, fset, and fdel corresponding to the constructor arguments.

Changed in version 3.5: The docstrings of property objects are now writeable.

先看一段代碼:

class stu:
    def __init__(self,name):
        self.name = name

    def get_score(self):
        return self.score

    def set_score(self, score):
        if not isinstance(score, int):
            raise ValueError("score must be an integer~")
        if score>100 or score<0:
            raise ValueError("score must between 0~100")
        self.score = score

s = stu("Botoo")
#s.set_score(100)            #score must be an integer~
#s.set_score("dasda")    #score must between 0~100
s.set_score(98)
print(s.get_score())        #98

這種使用 get/set 方法來封裝對一個屬性的訪問在許多面向對象編程的語言中都很常見。

但是寫 s.get_score() 和 s.set_score() 沒有直接寫 s.score 來得直接。

因為Python支持高階函數,可以用裝飾器函數把 get/set 方法“裝飾”成屬性調用:

再比較:

class Student:
    def __init__(self,name):
        self.name = name

    @property
    def score(self):
        return self._score

    @score.setter
    def score(self,value):
        if not isinstance(value, int):
            raise ValueError(分數必須是整數才行吶)
        if value < 0 or value > 100:
            raise ValueError(分數必須0-100之間)
        self._score = value
        
S1 = Student("botoo")
S1.score = 50

print(S1.score)         #50
S1.score = 500         #ValueError: 分數必須0-100之間

第一個score(self)是get方法,用@property裝飾,第二個score(self, score)是set方法,用@score.setter裝飾,@score.setter是前一個@property裝飾後的副產品。

在子類中擴展一個property可能會引起很多不易察覺的問題, 因為一個property其實是 gettersetterdeleter 方法的集合,而不是單個方法。 因此,當你擴展一個property的時候,你需要先確定你是否要重新定義所有的方法還是說只修改其中某一個。

參考:

http://python3-cookbook.readthedocs.io/zh_CN/latest/c08/p08_extending_property_in_subclass.html

https://blog.csdn.net/u013205877/article/details/77804137

python基礎===裝飾器@property