背景

  • 有场景分别定义两组逻辑,随后有统一入口做基类属性的整合
  • 其中两组逻辑的积累构造函数定义入参不同
  • 设计类继承图如:

  • 实际的使用方式抽象为[使用] 小节
  • 实际开发过程中遇到问题

先说结论

  • 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-多继承构造函数声明问题的更多相关文章

  1. [py]python的继承体系-源码目录结构

    python3安装目录 pip install virtualenv pip install virtualenvwrapper pip install virtualenvwrapper-win m ...

  2. Python中的构造函数

    Python中的构造函数是__init__函数.在Python中,子类如果定义了构造函数,而没有调用父类的,那么Python不会自动调用,也就是说父类的构造函数不会执行. 比如有test.py的mod ...

  3. C++11中的继承构造函数

    时间:2014.06.19 地点:基地 ------------------------------------------------------------------------- 一.问题描写 ...

  4. c++11 继承构造函数

    若基类拥有数量众多的不同版本的构造函数,而派生类中只有一些成员函数,则对于派生类而言,其构造函数就等同于构造基类. struct A { A(int i) {} A(double d, int i) ...

  5. python类变量与构造函数的使用

    类变量:可在类的所有实例之间共享的变量 实例类对象:类的实例是调用类对象来创建的.如:par = Parent(),par就是类Parent的一个实例类对象. 实例变量(成员变量):同一个类对象可以创 ...

  6. sqlalchemy mark-deleted 和 python 多继承下的方法解析顺序 MRO

    sqlalchemy mark-deleted 和 python 多继承下的方法解析顺序 MRO 今天在弄一个 sqlalchemy 的数据库基类的时候,遇到了跟多继承相关的一个小问题,因此顺便看了一 ...

  7. python基础——继承和多态

    python基础——继承和多态 在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类.父类或超类 ...

  8. js最好的继承机制:用对象冒充继承构造函数的属性,用原型prototype继承对象的方法。

    js最好的继承机制:用对象冒充继承构造函数的属性,用原型prototype继承对象的方法. function ClassA(sColor) { this.color = sColor; } Class ...

  9. [修]python普通继承方式和super继承方式

    [转]python普通继承方式和super继承方式 原文出自:http://www.360doc.com/content/13/0306/15/9934052_269664772.shtml 原文的错 ...

  10. python中的编码声明

    python中的第一行,目的就是指出,你想要你的这个文件中的代码用什么可执行程序去运行它,就这么简单 #!/usr/bin/python 相当于写死了 python 路径(是告诉OS执行这个py时,调 ...

随机推荐

  1. SSH客户端常用工具SecureCRT操作

    目录 1.1 SecureCRT工具介绍 1.2 SecureCRT工具安装 1.3配置SecureCRT连接Linux主机 1.4调整SecureCRT终端显示和回滚缓冲区大小 1.5调整字体及光标 ...

  2. vue下载附件按钮功能

    一.tools文件夹下tools文件中封装下载方法: const iframeId = 'download_file_iframe' function iframeEle (src) { let el ...

  3. 2022-12-12:有n个城市,城市从0到n-1进行编号。小美最初住在k号城市中 在接下来的m天里,小美每天会收到一个任务 她可以选择完成当天的任务或者放弃该任务 第i天的任务需要在ci号城市完成,

    2022-12-12:有n个城市,城市从0到n-1进行编号.小美最初住在k号城市中 在接下来的m天里,小美每天会收到一个任务 她可以选择完成当天的任务或者放弃该任务 第i天的任务需要在ci号城市完成, ...

  4. 2021-10-13:单词接龙。字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列:序列中第一个单词是 beginWord 。序列中最后

    2021-10-13:单词接龙.字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列:序列中第一个单词是 beginWord .序列中最后 ...

  5. springsecurity 认证,授权,注销,动态菜单,记住我和首页定制

    搭建环境: 1.在创建springboot时选择组件web,thymeleaf,spring-security 2.导入静态资源,导入后测试一下环境  认证和授权: 继承类WebSecurityCon ...

  6. odoo开发教程十三:qweb报表

    一:概述 报表是使用qweb定义的,报表的pdf导出是使用wkhtmltopdf来完成的. 如果需要为一个模型创建报表,需要定义report及对应模板. 如果有需要的话还可以指定特定的纸张格式, 如果 ...

  7. 烂怂if-else代码优化方案

    0.问题概述 代码可读性是衡量代码质量的重要标准,可读性也是可维护性.可扩展性的保证,因为代码是连接程序员和机器的中间桥梁,要对双边友好.Quora 上有一个帖子: "What are so ...

  8. elment UI + EasyExcel 实现 导入

    前端组件 <hd-flex> <el-dialog v-model="isUploadDialog" width="50%" lock-scr ...

  9. 从零玩转系列之微信支付实战PC端接口搭建

    一.前言 halo各位大佬很久没更新了最近在搞微信支付,因商户号审核了我半个月和小程序认证也找了资料并且将商户号和小程序进行关联,至此微信支付Native支付完成.此篇文章过长我将分几个阶段的文章发布 ...

  10. facebook搜索中的EBR检索技术-学习笔记

    简介 本文是论文Embedding-based Retrieval in Facebook Search的学习笔记 FB的社交搜索 搜索无处不在,搜索的种类多种多样,谷歌.百度.bing的全网搜索.淘 ...