Python如何在子类里扩展父类的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__函数吗?试试看:

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
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方法,就不行了,如下:

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
>>> 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在此,随时修改。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值