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在此,随时修改。
Python如何在子类里扩展父类的property?的更多相关文章
- python基础----继承与派生、组合、接口与归一化设计、抽象类、子类中调用父类方法
一.什么是继承 继承是一种创建新的类的方式,在pyth ...
- python基础之类的继承与派生、组合、接口与归一化设计、抽象类、子类中调用父类方法
一.什么是继承 继承是一种创建新的类的方式,新建的类可以继承自一个或者多个父类,原始类称为基类或超类,新建的类称为派生类或子类. 派生:子类继承了父类的属性,然后衍生出自己新的属性,如果子类衍生出的新 ...
- Python 在子类中调用父类方法详解(单继承、多层继承、多重继承)
Python 在子类中调用父类方法详解(单继承.多层继承.多重继承) by:授客 QQ:1033553122 测试环境: win7 64位 Python版本:Python 3.3.5 代码实践 ...
- Python之面向对象的组合、多态、菱形问题、子类中重用父类的两种方式
一.组合 ''' 1.什么是组合 组合就是一个类的对象具备某一个属性,该属性的值是指向另外一个类的对象 2.为何用组合 组合也是用来解决类与类直接代码冗余问题的 3.如何用组合 ''' # 继承减少代 ...
- js扩展父类方法
在网上找了很多一直没找到关于JS扩展父类的方法,让我很是郁闷啊~要是真的开发组遇到了该咋整,于是乎自己手写了一些测试代码,没想到通过了……(难道是人品太好了?)废话不多说了直接上代码看看~ <s ...
- [面向对象之继承应用(在子类派生重用父类功能(super),继承实现原理(继承顺序、菱形问题、继承原理、Mixins机制),组合]
[面向对象之继承应用(在子类派生重用父类功能(super),继承实现原理(继承顺序.菱形问题.继承原理.Mixins机制),组合] 继承应用 类与类之间的继承指的是什么'是'什么的关系(比如人类,猪类 ...
- Odoo(OpenERP) 多个子类重载同一个父类方法的执行顺序及如何调用父类的父类方法
首先说下起因,在修改英国会计模块(没错,就是那个安格鲁撒克逊记账模式!)中不符合中国国情的部分供能时,碰到了一个棘手的问题,简单的说就是B类继承它的父类A并重载了A的方法M,同时C类也继承了A类也重载 ...
- java 子类强转父类 父类强转子类
Java 继承 继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为. Java 子类强转父类 父类引用指向子类对象: jav ...
- 子类中执行父类的方法(引出super()与mro列表)
1. 我们先想一下在python中如果子类方法中想执行父类的方法,有什么方式?大概有三种: Parent.__init__(self, name) # 通过父类的名字,指定调用父类的方法 super( ...
随机推荐
- [019] Android平台调用WebService详解
http://blog.csdn.net/lyq8479/article/details/6428288/ http://www.cnblogs.com/gzggyy/archive/2011/06/ ...
- leetcode216
public class Solution { public IList<IList<int>> CombinationSum3(int k, int n) { , , , , ...
- Java的单向加密算法MD5和SHA——加密和解密
出自:http://www.cnblogs.com/onetwo/p/3875551.html 1.JDK中MD5和SHA加密的主要类 在JDK6.0中,与MD5与SHA密切相关的几个类的类图如下: ...
- Coins and Queries(codeforce 1003D)
Polycarp has nn coins, the value of the i-th coin is aiai . It is guaranteed that all the values are ...
- for in 循环的输出顺序问题
var data = { '4': 'first', '3': 'second', '2': 'third', '1': 'fourth' }; for (var i in data) { conso ...
- POJ1161(并查集)
1.题目链接地址 http://poj.org/problem?id=1161 2.源代码 #include <iostream> using namespace std; ]; ]; i ...
- (转)Mac下MySql安装经历(含安装错误排查、卸载多种折腾)
在安装mysql的时候,活活折腾我两天.结果终于被我折腾成功了……一开始我就放了个错误:我下了32位版本的mysql:mysql-5.5.8-osx10.6-x86.dmg 须知在mac下装的是64位 ...
- IDEA02 利用Maven创建Web项目、为Web应用添加Spring框架支持、bean的创建于获取、利用注解配置Bean、自动装配Bean、MVC配置
1 环境版本说明 Jdk : 1.8 Maven : 3.5 IDEA : 专业版 2017.2 2 环境准备 2.1 Maven安装及其配置 2.2 Tomcat安装及其配置 3 详细步骤 3.1 ...
- ROS编译:catkin简析
博客转载自:https://blog.csdn.net/zyh821351004/article/details/50388429 Catkin tutorials: http://wiki.ros. ...
- linux环境配置与使用合集
配置linux和samba共享 1. 安装linux操作系统 2. 通过windows操作系统ping linux看看是否可以ping通 3. 相关软件安装 a. 安装samba sudo apt-g ...