Python2出现unbound method __init__()错误,Python3正常的原因与解决
Python2与Python3中跨类调用构造函数的差异与兼容方案
问题现象
以下代码在Python3中运行正常,但在Python2.7中会抛出类型错误:
class Base: def __init__(self): print("base constructor") class derived(Base): def __init__(self): print("derived constructor") class Secondary(Base): def __init__(self): derived.__init__(self) s = Secondary()
Python2.7执行报错:
$ python2.7 test.py Traceback (most recent call last): File "test.py", line 13, in <module> s = Secondary() File "test.py", line 11, in __init__ derived.__init__(self) TypeError: unbound method __init__() must be called with derived instance as first argument (got Secondary instance instead)
尝试改用super(已让Base继承object)后,Python2.7仍报错:
class Base(object): def __init__(self): print("base constructor") class derived(Base): def __init__(self): print("derived constructor") class Secondary(Base): def __init__(self): super(derived, self).__init__() s = Secondary()
报错信息:
$ python2.7 test.py Traceback (most recent call last): File "test.py", line 13, in <module> s = Secondary() File "test.py", line 11, in __init__ super(derived, self).__init__() TypeError: super(type, obj): obj must be an instance or subtype of type
原因分析
Python2与Python3的方法绑定机制差异
- Python2中,类的方法默认是未绑定方法,调用时会严格检查第一个参数的实例类型是否属于该类或其子类。
derived.__init__作为未绑定方法,要求传入的self必须是derived的实例,而Secondary实例不符合要求,因此报错。 - Python3中,类的方法被视为普通函数,不再做强制的类型检查,只要传入的参数符合方法定义即可执行,因此
derived.__init__(self)能正常运行。
- Python2中,类的方法默认是未绑定方法,调用时会严格检查第一个参数的实例类型是否属于该类或其子类。
super的用法错误
使用super(derived, self)时,super要求第二个参数self必须是第一个参数derived的实例或子类实例,但self是Secondary的实例,和derived没有继承关系,因此触发类型错误。
兼容Python2的解决方案
方案1:调用方法的底层函数跳过类型检查
在Python2中,可以通过__func__属性直接获取方法对应的底层函数,绕开未绑定方法的类型检查:
class Base: def __init__(self): print("base constructor") class derived(Base): def __init__(self): print("derived constructor") class Secondary(Base): def __init__(self): derived.__init__.__func__(self) s = Secondary()
方案2:调整继承关系后正确使用super
如果业务允许Secondary继承自derived而非Base,可以正常使用super实现逻辑复用:
class Base(object): def __init__(self): print("base constructor") class derived(Base): def __init__(self): print("derived constructor") super(derived, self).__init__() class Secondary(derived): def __init__(self): super(Secondary, self).__init__() s = Secondary()
方案3:直接复用构造逻辑(不推荐)
如果只是想复用derived的构造逻辑,也可以提取独立函数供两个类调用,避免跨类调用构造函数的问题:
class Base: def __init__(self): print("base constructor") def derived_init_logic(): print("derived constructor") class derived(Base): def __init__(self): derived_init_logic() class Secondary(Base): def __init__(self): derived_init_logic() s = Secondary()
内容的提问来源于stack exchange,提问作者roulette01
相关产品推荐
相关产品推荐

