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 "", line 1, in sp = SubPerson('shy') File "", line 3, in __init__ self.name = name File "", 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__, ) | 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 "", line 1, in sp = SubPerson('shy') File "", 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在此,随时修改。https://www.cnblogs.com/telecomshy/p/10172615.html
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信