Python 子类调用父类构造函数的两种实现方式
在 Python 面向对象编程中,子类重写构造函数时若不调用父类初始化方法,将导致父类属性缺失。本文详解通过 super() 函数和显式调用父类类名两种方式实现父类构造函数的调用,并对比 Python 2 与 Python 3 在语法上的差异。
问题背景:子类未调用父类构造函数的后果
当子类继承父类并重写 __init__ 方法时,如果忘记调用父类的初始化函数,父类中定义的属性将无法在子类实例中初始化。这会导致在访问父类属性或调用父类方法时抛出 AttributeError 错误。
class A(object):
def __init__(self):
self.nameaa = 'aa'
def funca(self):
print('function a %s' % self.nameaa)
class B(A):
def __init__(self):
self.namebb = 'bb'
def funcb(self):
print('function b %s' % self.namebb)
b = B()
print(b.namebb) # 输出: bb
b.funcb() # 输出: function b bb
print(b.nameaa) # 报错: AttributeError: 'B' object has no attribute 'nameaa'
解决方案一:显式调用父类构造函数
最直接的方式是在子类的 __init__ 中,通过父类名直接调用其 __init__ 方法。这种方式在 Python 2 和 Python 3 中均适用。
class A(object):
def __init__(self):
self.nameaa = 'aa'
def funca(self):
print('function a %s' % self.nameaa)
class B(A):
def __init__(self):
self.namebb = 'bb'
A.__init__(self) # 显式调用父类构造函数
def funcb(self):
print('function b %s' % self.namebb)
b = B()
print(b.namebb) # 输出: bb
b.funcb() # 输出: function b bb
print(b.nameaa) # 输出: aa
b.funca() # 输出: function a aa
解决方案二:使用 super() 函数
super() 函数用于返回一个当前类的父类代理对象,它会自动处理多重继承中的方法解析顺序(MRO)。这是更推荐的面向对象编程方式。
class A(object):
def __init__(self):
self.nameaa = 'aa'
def funca(self):
print('function a %s' % self.nameaa)
class B(A):
def __init__(self):
self.namebb = 'bb'
super(B, self).__init__() # 调用父类构造函数
def funcb(self):
print('function b %s' % self.namebb)
b = B()
print(b.namebb) # 输出: bb
b.funcb() # 输出: function b bb
print(b.nameaa) # 输出: aa
b.funca() # 输出: function a aa
特殊情况:子类未重写构造函数
如果子类没有定义 __init__ 方法,Python 会自动调用父类的构造函数。此时子类实例可以直接使用父类的属性和方法。
class A(object):
def __init__(self):
self.nameaa = 'aa'
def funca(self):
print('function a %s' % self.nameaa)
class C(A):
pass # 未重写构造函数
c = C()
c.funca() # 输出: function a aa
print(c.nameaa) # 输出: aa
Python 2 与 Python 3 的差异
在 Python 3 中,super() 可以不带参数调用,解释器会自动推断当前类和实例。而在 Python 2 中,必须显式传递类名和 self 参数。
Python 3 写法(推荐)
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
@author: Frank
@contact: frank.chang@shoufuyou.com
@file: py2topy3.py
@time: 2018/7/7 上午7:09
## python3 代码
"""
import threading
import queue # Python 3 中模块名为小写 queue
_sentinel = object()
class Consumer(threading.Thread):
"""
消费者线程类
"""
def __init__(self, name, queue):
super().__init__(name=name) # Python 3 无需传递参数
self.queue = queue
def run(self):
while True:
values = self.queue.get(timeout=None)
if values is _sentinel:
self.queue.put(values)
break
##process values
##xxx
print('consume is consuming data {}'.format(values))
print("{} finished".format(self.getName()))
if __name__ == '__main__':
q = queue.Queue()
concumser = Consumer('consumer', q)
print(concumser)Python 2 写法
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
@author: Frank
@contact: frank.chang@shoufuyou.com
@file: 3.py
@time: 2018/7/7 上午7:05
"""
import Queue # Python 2 中模块名为大写 Queue
import threading
# 哨兵
_sentinel = object()
class Consumer(threading.Thread):
"""
消费者线程类
"""
def __init__(self, name, queue):
super(Consumer, self).__init__(name=name) # Python 2 需传递类名和 self
self.queue = queue
def run(self):
while True:
values = self.queue.get(timeout=None)
if values is _sentinel:
self.queue.put(values)
break
##process values
##xxx
print('consume is consuming data {}'.format(values))
print("{} finished".format(self.getName()))
if __name__ == '__main__':
q = Queue.Queue()
concumser = Consumer('consumer', q)
print(concumser)以上就是 Python 子类调用父类构造函数的详细内容,更多关于 Python 继承与 super() 的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









