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__函数吗?试试看:网址:yii666.com文章来源地址:https://www.yii666.com/article/758043.html

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),才发现蛛丝马迹:文章来源地址https://www.yii666.com/article/758043.html

>>> 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方法,就不行了,如下:文章地址https://www.yii666.com/article/758043.html网址:yii666.com<

>>> 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在此,随时修改。

版权声明:本文内容来源于网络,版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。文本页已经标记具体来源原文地址,请点击原文查看来源网址,站内文章以及资源内容站长不承诺其正确性,如侵犯了您的权益,请联系站长如有侵权请联系站长,将立刻删除

Python如何在子类里扩展父类的property?-相关文章

  1. js获得焦点和失去焦点那些事

  2. 【转】子类会调用父类的@PostConstruct方法

  3. 在子类中调用父类的方法super

  4. Python之面向对象的组合、多态、菱形问题、子类中重用父类的两种方式

  5. 通过父类定位到子类 先将父类当作一个dom

  6. Python如何在子类里扩展父类的property?

  7. [问题解决]NotImplementedError 错误原因:子类没有实现父类要求一定要实现的接口

    NotImplementedError: 子类没有实现父类要求一定要实现的接口。在面向对象编程中,父类中可以预留一个接口不实现,要求在子类中实现。如果一定要子类中实现该方法,可以使用raise NotImplementedError报错。具体实现方式:如果子类没有实现父类中指定要实现的方法,则会自动调用

  8. 113.dynamic_cast 虚函数 通过子类初始化的父类转化为子类类型

    #include iostream using namespace std; //子类同名函数覆盖父类 //父类指针存储子类地址,在有虚函数情况会调用子类方法,否则会调用父类方法 class base { public: virtual void show() { cout \\\"base show\\\" endl; } }; class baseX : public base { public: void show() { cout \\\"baseX show\\\" endl; } }; void main() { base *p1 = new baseX;

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信图片_20190322181744_03.jpg

微信扫一扫打赏

请作者喝杯咖啡吧~

支付宝扫一扫领取红包,优惠每天领

二维码1

zhifubaohongbao.png

二维码2

zhifubaohongbao2.png