python-多继承构造函数声明问题
背景
- 有场景分别定义两组逻辑,随后有统一入口做基类属性的整合
- 其中两组逻辑的积累构造函数定义入参不同
- 设计类继承图如:
- 实际的使用方式抽象为[使用] 小节
- 实际开发过程中遇到问题
先说结论
- python 多继承,需要使用super函数进行MRO的依次不重复初始化
- python 多继承的情况下,构造函数__init__会被依次调用并传递参数
- python 多继承情况下,__init__参数需要保持一致,否则会出现某些继承路径上的基类初始化遇到异常
- python 多继承情况下,若构造函数参数不一致,可通过(*args, **kwargs)来统一
- python 多继承情况下,若有公共基类,MRO可被调整为有跳跃路径,进而利用子类不同的构造函数完成正常初始化,但需要临近基类可以处理子类传来的所有参数。
使用
# tjc = TestJobConfiger()
tjc = SubTest()
print vars(tjc)
print "\n".join([tjc.base_key,
tjc.base1_key,
tjc.subbase_key,
tjc.subbase1_key,
tjc.subtest_key])
期望结果
enter Base
enter SubBase
enter Base1|_arg1 |_arg2
enter SubBase1|_arg1 |_arg2
vars : {'base1_key': 'base1_key', 'subtest_key': 'subtest_key', 'subbase1_key': 'subbase1_key', 'subbase_key': 'subbase_key', 'base_key': 'base_key'}
values: base_key
base1_key
subbase_key
subbase1_key
subtest_key
第一版实现
class Base(object):
def __init__(self):
print "enter Base"
self.base_key = "base_key"
class Base1(object):
def __init__(self, _arg1 = "_arg1 ", _arg2 = "_arg2 "):
print "enter Base1" + "|" + _arg1 + "|" + _arg2
self.base1_key = "base1_key"
class SubBase(Base):
def __init__(self):
super(SubBase, self).__init__()
print "enter SubBase"
self.subbase_key = "subbase_key"
class SubBase1(Base1):
def __init__(self, _arg1 = "_arg1 ", _arg2 = "_arg2 "):
super(SubBase1, self).__init__(_arg1 = _arg1, _arg2=_arg2)
print "enter SubBase1" + "|" + _arg1 + "|" + _arg2
self.subbase1_key = "subbase1_key"
class SubTest(SubBase,SubBase1):
def __init__(self, _arg1 = "_arg1 "):
super(SubTest, self).__init__(_arg1=_arg1, _arg2="None")
# self.__dict__.update(vars(SubBase()))
self.subtest_key = "subtest_key"
- 运行结果为:
Traceback (most recent call last):
File "/Users/enzhao/suanec/ksp/dispatch/weiclient/client/weiclient/libs/com/weibo/tools/job_manager/job_configer_tester.py", line 43, in <module>
tjc = SubTest()
File "/Users/enzhao/suanec/ksp/dispatch/weiclient/client/weiclient/libs/com/weibo/tools/job_manager/job_configer_tester.py", line 38, in __init__
super(SubTest, self).__init__(_arg1=_arg1, _arg2="None")
TypeError: __init__() got an unexpected keyword argument '_arg1'
第二版实现
class Base(object):
def __init__(self):
print "enter Base"
self.base_key = "base_key"
class Base1(object):
def __init__(self, _arg1 = "_arg1 ", _arg2 = "_arg2 "):
print "enter Base1" + "|" + _arg1 + "|" + _arg2
self.base1_key = "base1_key"
class SubBase(Base):
def __init__(self, **kwargs):
super(SubBase, self).__init__()
print "enter SubBase"
self.subbase_key = "subbase_key"
class SubBase1(Base1):
def __init__(self, _arg1 = "_arg1 ", _arg2 = "_arg2 "):
super(SubBase1, self).__init__(_arg1 = _arg1, _arg2=_arg2)
print "enter SubBase1" + "|" + _arg1 + "|" + _arg2
self.subbase1_key = "subbase1_key"
class SubTest(SubBase,SubBase1):
def __init__(self, _arg1 = "_arg1 "):
super(SubTest, self).__init__(_arg1=_arg1, _arg2="None")
# self.__dict__.update(vars(SubBase()))
self.subtest_key = "subtest_key"
- 运行结果为:
Traceback (most recent call last):
enter Base
enter SubBase
File "/Users/enzhao/suanec/ksp/dispatch/weiclient/client/weiclient/libs/com/weibo/tools/job_manager/job_configer_tester.py", line 46, in <module>
vars : {'subtest_key': 'subtest_key', 'subbase_key': 'subbase_key', 'base_key': 'base_key'}
tjc.base1_key,
AttributeError: 'SubTest' object has no attribute 'base1_key'
二次继承实现
class Base(object):
def __init__(self):
print "enter Base"
self.base_key = "base_key"
class Base1(Base):
def __init__(self, _arg1 = "_arg1 ", _arg2 = "_arg2 "):
super(Base1, self).__init__()
print "enter Base1" + "|" + _arg1 + "|" + _arg2
self.base1_key = "base1_key"
class SubBase(Base):
def __init__(self, **kwargs):
super(SubBase, self).__init__()
print "enter SubBase"
self.subbase_key = "subbase_key"
class SubBase1(Base1):
def __init__(self, _arg1 = "_arg1 ", _arg2 = "_arg2 "):
super(SubBase1, self).__init__(_arg1 = _arg1, _arg2=_arg2)
print "enter SubBase1" + "|" + _arg1 + "|" + _arg2
self.subbase1_key = "subbase1_key"
class SubTest(SubBase,SubBase1):
def __init__(self, _arg1 = "_arg1 "):
super(SubTest, self).__init__(_arg1=_arg1, _arg2="None")
# self.__dict__.update(vars(SubBase()))
self.subtest_key = "subtest_key"
- 运行结果为:
enter Base
enter Base1|_arg1 |_arg2
enter SubBase1|_arg1 |_arg2
enter SubBase
vars : {'base1_key': 'base1_key', 'subtest_key': 'subtest_key', 'subbase_key': 'subbase_key', 'subbase1_key': 'subbase1_key', 'base_key': 'base_key'}
values: base_key
base1_key
subbase_key
subbase1_key
subtest_key
公共基类实现
class BBase(object):
def __init__(self):
pass
class Base(BBase):
def __init__(self):
print "enter Base"
self.base_key = "base_key"
class Base1(BBase):
def __init__(self, _arg1 = "_arg1 ", _arg2 = "_arg2 "):
print "enter Base1" + "|" + _arg1 + "|" + _arg2
self.base1_key = "base1_key"
class SubBase(Base):
def __init__(self, **kwargs):
super(SubBase, self).__init__()
print "enter SubBase"
self.subbase_key = "subbase_key"
class SubBase1(Base1):
def __init__(self, _arg1 = "_arg1 ", _arg2 = "_arg2 "):
super(SubBase1, self).__init__(_arg1 = _arg1, _arg2=_arg2)
print "enter SubBase1" + "|" + _arg1 + "|" + _arg2
self.subbase1_key = "subbase1_key"
class SubTest(SubBase,SubBase1):
def __init__(self, _arg1 = "_arg1 "):
super(SubTest, self).__init__(_arg1=_arg1, _arg2="None")
# self.__dict__.update(vars(SubBase()))
self.subtest_key = "subtest_key"
- 运行结果为:
enter Base
enter SubBase
vars : {'subtest_key': 'subtest_key', 'subbase_key': 'subbase_key', 'base_key': 'base_key'}
Traceback (most recent call last):
File "/Users/enzhao/suanec/ksp/dispatch/weiclient/client/weiclient/libs/com/weibo/tools/job_manager/job_configer_tester.py", line 50, in <module>
tjc.base1_key,
AttributeError: 'SubTest' object has no attribute 'base1_key'
Hack实现
- 分别保持各自定义逻辑
- 在入口子类中,声明冲突基类的对象,利用python的vars和__dict__的特性进行属性的声明
- 相当于手动hard-code 构造函数的调用,完成基类的初始化
class Base(object):
def __init__(self):
print "enter Base"
self.base_key = "base_key"
class Base1(object):
def __init__(self, _arg1 = "_arg1 ", _arg2 = "_arg2 "):
print "enter Base1" + "|" + _arg1 + "|" + _arg2
self.base1_key = "base1_key"
class SubBase(Base):
def __init__(self):
super(SubBase, self).__init__()
print "enter SubBase"
self.subbase_key = "subbase_key"
class SubBase1(Base1):
def __init__(self, _arg1 = "_arg1 ", _arg2 = "_arg2 "):
super(SubBase1, self).__init__(_arg1 = _arg1, _arg2=_arg2)
print "enter SubBase1" + "|" + _arg1 + "|" + _arg2
self.subbase1_key = "subbase1_key"
class SubTest(SubBase1):
def __init__(self, _arg1 = "_arg1 "):
super(SubTest, self).__init__(_arg1=_arg1, _arg2="None")
self.__dict__.update(vars(SubBase()))
self.subtest_key = "subtest_key"
- 运行结果为:
enter Base1|_arg1 |None
enter SubBase1|_arg1 |None
enter Base
enter SubBase
vars : {'base1_key': 'base1_key', 'subtest_key': 'subtest_key', 'subbase_key': 'subbase_key', 'subbase1_key': 'subbase1_key', 'base_key': 'base_key'}
values: base_key
base1_key
subbase_key
subbase1_key
subtest_key
官方建议实现
class A(object):
def __init__(self, *args, **kwargs):
print "A"
class B(object):
def __init__(self, *args, **kwargs):
print "B"
class C(A):
def __init__(self, arg, *args, **kwargs):
print "C","arg=",arg
super(C, self).__init__(arg, *args, **kwargs)
class D(B):
def __init__(self, arg, *args, **kwargs):
print "D", "arg=",arg
super(D, self).__init__(arg, *args, **kwargs)
class E(C,D):
def __init__(self, arg, *args, **kwargs):
print "E", "arg=",arg
super(E, self).__init__(arg, *args, **kwargs)
print "MRO:", [x.__name__ for x in E.__mro__]
E(10)
MRO: ['E', 'C', 'A', 'D', 'B', 'object']
E arg= 10
C arg= 10
A
结论
- 放最前面说吧
python-多继承构造函数声明问题的更多相关文章
- [py]python的继承体系-源码目录结构
python3安装目录 pip install virtualenv pip install virtualenvwrapper pip install virtualenvwrapper-win m ...
- Python中的构造函数
Python中的构造函数是__init__函数.在Python中,子类如果定义了构造函数,而没有调用父类的,那么Python不会自动调用,也就是说父类的构造函数不会执行. 比如有test.py的mod ...
- C++11中的继承构造函数
时间:2014.06.19 地点:基地 ------------------------------------------------------------------------- 一.问题描写 ...
- c++11 继承构造函数
若基类拥有数量众多的不同版本的构造函数,而派生类中只有一些成员函数,则对于派生类而言,其构造函数就等同于构造基类. struct A { A(int i) {} A(double d, int i) ...
- python类变量与构造函数的使用
类变量:可在类的所有实例之间共享的变量 实例类对象:类的实例是调用类对象来创建的.如:par = Parent(),par就是类Parent的一个实例类对象. 实例变量(成员变量):同一个类对象可以创 ...
- sqlalchemy mark-deleted 和 python 多继承下的方法解析顺序 MRO
sqlalchemy mark-deleted 和 python 多继承下的方法解析顺序 MRO 今天在弄一个 sqlalchemy 的数据库基类的时候,遇到了跟多继承相关的一个小问题,因此顺便看了一 ...
- python基础——继承和多态
python基础——继承和多态 在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类.父类或超类 ...
- js最好的继承机制:用对象冒充继承构造函数的属性,用原型prototype继承对象的方法。
js最好的继承机制:用对象冒充继承构造函数的属性,用原型prototype继承对象的方法. function ClassA(sColor) { this.color = sColor; } Class ...
- [修]python普通继承方式和super继承方式
[转]python普通继承方式和super继承方式 原文出自:http://www.360doc.com/content/13/0306/15/9934052_269664772.shtml 原文的错 ...
- python中的编码声明
python中的第一行,目的就是指出,你想要你的这个文件中的代码用什么可执行程序去运行它,就这么简单 #!/usr/bin/python 相当于写死了 python 路径(是告诉OS执行这个py时,调 ...
随机推荐
- B/S结构系统的会话机制(session)
B/S结构系统的会话机制(session) 目录 B/S结构系统的会话机制(session) 每博一文案 1. session 会话机制的概述 2. 什么是 session 的会话 3. sessio ...
- Tomacat乱码和报错UTF-8 序列的字节 2 无效和‘application/json;charset=UTF-8‘ not supported的处理
文章目录 前言 1. tomcat乱码的处理方法 2. applicationContext.xml报错2 字节的 UTF-8 序列的字节 2 无效 3. 报错'application/json;ch ...
- [python] Python类型提示总结
Python3.5 版本引入了类型提示(Type Hints),它允许开发者在代码中显式地声明变量.函数.方法等的类型信息.这种类型声明不会影响 Python 解释器的运行,但可以让 IDE 和静态分 ...
- 2021-05-16:时间复杂度必须是logN,如何求阶乘从右向左第一个不为零的数?
2021-05-16:时间复杂度必须是logN,如何求阶乘从右向左第一个不为零的数? 福大大 答案2021-05-16: 这道题logN的解法是大步小步法,网上非常难找.另外论代码简洁度,明显是我的代 ...
- 2021-10-16:单词拆分 II。给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,在字符串中增加空格来构建一个句子,使得句子中所有的单词都在词典中。返回所有这些可能的句子。
2021-10-16:单词拆分 II.给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,在字符串中增加空格来构建一个句子,使得句子中所有的单词都在词典中.返回所有这些可能的句子. ...
- 【Qt 6】读写剪贴板
剪贴板是个啥就不用多介绍了,最直观的功能是实现应用程序之间数据共享.就是咱们常说的"复制"."粘贴"功能. 在 Qt 中,QClipboard 类提供了相关 A ...
- Python基础 - 第一个python程序
Python程序是什么? Python源程序就是一个特殊格式的文本文件,可以使用任意文本编辑器软件做python的开发,python的文件扩展名为 .py 执行python程序的三种方式 直接调用解释 ...
- Multiserver游戏服务器Demo[C++&Lua]
代码参考 代码文件参考下述详解的类图,工程参考第零章工程说明 关键特性 对Socket库进行封装,抹平Socket的Window&Linux的平台差异. C++嵌入lua脚本,增加开发者编码效 ...
- 有JSDoc还需要TypeScript吗
这听起来是不是很耳熟:你想写一个小型脚本,不管是为页面.命令行工具,还是其他什么类型.你从JavaScript开始,直到你想起写代码时没有类型是多么痛苦.所以你把文件从.js重命名为.ts.然后意识到 ...
- 【python基础】复杂数据类型-列表类型(增删改查)
1.初识列表(list) 列表由一系列按特定顺序排列的数据元素组成.可以将任何类型数据元素加入列表中,其中的数据元素之间没有任何关系.鉴于列表通常包含多个数据元素,给列表指定一个表示复数的名称是个不错 ...