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时,调 ...
随机推荐
- OpenAI CLIP 关键点 - 连接图像和文字
标签: #CLIP #Image2Text #Text2Image #OpenAI 创建时间:2023-04-21 00:17:52 基本原理 CLIP是一个图像分类模型. 准备训练数据:准备大量的文 ...
- 如何理解 Spring Boot 中的 Starter ?
假如 没有 Spring Boot Starter,我们有两种方式来创建 Spring Bean. spring xml 模式 (远古模式,并不推荐) spring API 来创建 Spring Be ...
- 2022-09-23:整数数组 stations 表示 水平数轴 上各个加油站的位置。给你一个整数 k 。 请你在数轴上增设 k 个加油站, 新增加油站可以位于 水平数轴 上的任意位置,而不必放在整数
2022-09-23:整数数组 stations 表示 水平数轴 上各个加油站的位置.给你一个整数 k . 请你在数轴上增设 k 个加油站, 新增加油站可以位于 水平数轴 上的任意位置,而不必放在整数 ...
- Selenium - 浏览器配置(3) - 沙盒模式/不打开浏览器运行
Selenium - 浏览器配置 沙盒模式 需要在Linux环境中运行,但不需要打开浏览器进行UI测试,可以加载selenium的无痕模式: 如果使用沙盒模式运行selenium,则部分seleniu ...
- hasattr()、getattr()、setattr()函数简介
hasattr(object, name) 判断object对象中是否存在name属性,当然对于python的对象而言,属性包含变量和方法:有则返回True,没有则返回False:需要注意的是name ...
- ubuntu配置vscode全过程(下载安装配置优化插件)
一.安装vscode 下载vscode 当然啦,我们安装vscode,当然要先下载啦,但是但是但是!不要在ubuntu的软件中心(Ubuntu Software)下载!贼坑!下载完不能用! 推荐下载方 ...
- vue 一键导出数据为excel文件并附带样式 十分简单
自入行以来我就一直疑惑一个问题,导出excel为什么总是搞的很复杂,包括网上的教程,屎里淘金,非常耗费精力.今天刚好业务需要,整理一个简单明了的由vue前端导出的版本出来. 开始: #1.添加xlsx ...
- GitHub 私有仓库完全免费且不限制协作人数
GitHub is now free for teams GitHub CEO Nat Friedman 在 2020.04.14 宣布已面向全体 GitHub 用户和团队提供不限制协作人数的私有仓库 ...
- OCR -- 文本识别 -- 实践篇
OCR -- 文本识别 -- 理论篇 本章将详细介绍如何基于PaddleOCR完成CRNN文本识别模型的搭建.训练.评估和预测.数据集采用 icdar 2015,其中训练集有4468张,测试集有207 ...
- WPF入门教程系列二十八 ——DataGrid使用示例MVVM模式(5)
WPF入门教程系列目录 WPF入门教程系列二--Application介绍 WPF入门教程系列三--Application介绍(续) WPF入门教程系列四--Dispatcher介绍 WPF入门教程系 ...