1. 程式人生 > >Python如何在子類裡擴充套件父類的property?

Python如何在子類裡擴充套件父類的property?

《python cookbook》8.8節討論子類擴充套件property時,一開始都暈了,思考了半天才勉強弄懂一點,趕快記下來。廢話不多說,先上程式碼:

class Person:
    def __init__(self, name):
        self.name = name
    @property
    def name(self):
        print("I am in the Person's name getter")  
        return self._name
    @name.setter
    def name(self, value):
        print("I am in the Person's name setter")
        if not isinstance(value, str):
            raise TypeError('Expected a string')
        self._name = value

class SubPerson(Person):
    @property
    def name(self):
        print("I am in the SubPerson's name getter")
        super().name
    @name.setter
    def name(self, value):
        print("I am in the SubPerson's name setter")
        super(SubPerson, SubPerson).name.__set__(self, value)

我知道property其實就是特殊的描述符,但是為啥在setter裡面必須顯式呼叫父類name的__set__函式呢?直接super().name = value難道不能觸發__set__函式嗎?試試看:

class SubPerson(Person):
    @property
    def name(self):
        print("I am in the SubPerson's name getter")
        super().name
    @name.setter
    def name(self, value):
        print("I am in the SubPerson's name setter")
        super().name = value

        
>>> sp = SubPerson('shy')
I am in the SubPerson's name setter
Traceback (most recent call last):
  File "<pyshell#25>", line 1, in <module>
    sp = SubPerson('shy')
  File "<pyshell#11>", line 3, in __init__
    self.name = name
  File "<pyshell#24>", line 9, in name
    super().name = value
AttributeError: 'super' object has no attribute 'name'

果然報錯,提示super物件沒有name屬性,WTF!為什麼可以get但是不能set?一直沒有查到答案,最後help(super),才發現蛛絲馬跡:

>>> help(super)
              
Help on class super in module builtins:

class super(object)
 |  super() -> same as super(__class__, <first argument>)
 |  super(type) -> unbound super object
 |  super(type, obj) -> bound super object; requires isinstance(obj, type)
 |  super(type, type2) -> bound super object; requires issubclass(type2, type)
 |  Typical use to call a cooperative superclass method:
 |  class C(B):
 |      def meth(self, arg):
 |          super().meth(arg)
 |  This works for class methods too:
 |  class C(B):
 |      @classmethod
 |      def cmeth(cls, arg):
 |          super().cmeth(arg)
 |  
 |  Methods defined here:
 |  
 |  __get__(self, instance, owner, /)
 |      Return an attribute of instance, which is of type owner.
 |  
 |  __getattribute__(self, name, /)
 |      Return getattr(self, name).
 |  
 |  __init__(self, /, *args, **kwargs)
 |      Initialize self.  See help(type(self)) for accurate signature.
 |  
 |  __new__(*args, **kwargs) from builtins.type
 |      Create and return a new object.  See help(type) for accurate signature.
 |  
 |  __repr__(self, /)
 |      Return repr(self).
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __self__
 |      the instance invoking super(); may be None
 |  
 |  __self_class__
 |      the type of the instance invoking super(); may be None
 |  
 |  __thisclass__
 |      the class invoking super()

super本身只有__getattribute__,沒有__setattr__,只對獲取屬性做了代理。因此設定的時候,會直接設定super()物件本身的屬性,所以出現如上的錯誤提示,因此只能夠顯式呼叫name的__set__方法。。。。

另外一個坑就是如果子類全面擴充套件父類的property,可以用上面的方法,但是如果只是擴充套件get或者set方法,就不行了,如下:

>>> class SubPerson(Person):
    @property
    def name(self):
        print("I am in SubPerson's getter")
        super().name

              
>>> sp = SubPerson('shy')
              
Traceback (most recent call last):
  File "<pyshell#48>", line 1, in <module>
    sp = SubPerson('shy')
  File "<pyshell#11>", line 3, in __init__
    self.name = name
AttributeError: can't set attribute

父類的setter方法消失了,這裡比較好理解,property是描述符,是get,set,delete的集合,子類僅僅只設定了get,set和delete相當於根本沒有設定。如果想要繼承父類的property,只能顯式的用父類的property來裝飾,如下:

>>> class SubPerson(Person):
    @Person.name.getter
    def name(self):
        print("I am in SubPerson's getter")
        return super().name

              
>>> sp = SubPerson('shy')
              
I am in the Person's name setter
>>> sp.name
              
I am in SubPerson's getter
I am in the Person's name getter
'shy'

此時返回的name特性,其實是複製了Person.name描述符所有方法的一個新的描述符。。
擴充套件子類的property,需要對描述符和super的機制有比較深入的瞭解,現在只是模模糊糊弄了個半懂,mark在此,隨時修改。

鄭州哪家男科醫院好

鄭州婦科醫院哪好

鄭州醫院哪家看男科好

鄭州哪家醫院看男科好