1. 程式人生 > >Python類與物件技巧(2):拓展子類屬性

Python類與物件技巧(2):拓展子類屬性

更多的時候,我們需要拓展父類中property的功能。

class Person:
    def __init__(self, name):
        self.name = name
    
    # Getter funtion
    @property
    def name(self):
        return self._name
        
    # Setter  function
    @name.setter
    def name(self, value):
        if not isinstance(value, str):
            raise TypeError('Expected a string')
        self._name = value

    #Deleter function
    @name.deleter
    def name(self):
        raise AttributeError("Can't delete attribute")

class SubPerson(Person):
    @property
    def name(self):
        print('Getting parent class name')
        return super().name
 
    @name.setter
    def name(self, value):
        print('Setting name to', value)
        super(SubPerson, SubPerson).name.__set__(self, value)

    @name.deleter
    def name(self):
        print('Deleting name')
        super(SubPerson, SubPerson).name.__delete__(self)

p = SubPerson('ziheng')
# >>> Setting name to ziheng
print(p.name)
# >>> Getting parent class name
#     ziheng
p.name = 'chunxu'        
# >>> Setting name to chunxu  

在子類中擴充套件一個property可能會引起很多不易察覺的問題。 因為property其實是 getter、setter 和 deleter 方法的集合,而不是單個方法。 因此,當擴充套件property的時候,需要先確定是否要重新定義所有方法還是隻修改其中一個。 在該例子中,所有的property方法都被重新定義。 在每個方法中,使用了 super() 來呼叫父類的實現。

在 setter 函式中使用 super(SubPerson, SubPerson).name.__set__(self, value) 的語句是沒有錯的。 為了委託給之前定義的setter方法,需要將控制權傳遞給之前定義的name屬性的 __set__() 方法。 不過,獲取這個方法的唯一途徑是使用類變數而不是例項變數來訪問它。 這也是為什麼要使用 super(SubPerson, SubPerson) 的原因。

如果只想重定義其中一個方法,那隻使用 @property 本身是不夠的

錯誤程式碼例項;

class SubPerson(Person):
    @property  # Doesn't work
    def name(self):
        print('Getting name')
        return super().name

s = SubPerson('ziheng')
# >>> Traceback (most recent call last):
#       File "<stdin>", line 1, in <module>
#       File "****.py", line 5, in __init__
#            self.name = name
#    AttributeError: can't set attribute

正確程式碼例項:

class SubPerson(Person):
    @Person.name.getter
    def name(self):
        print('Getting name')
        return super().name
s = SubPerson('ziheng')
print(s.name)
# >>> Getting name
#     'ziheng'

博文參考《python3-cookbook》