转:super().__init__()详解

本文通过三个测试案例详细解析了Python中super()函数在单继承中的使用方法及作用,阐述了其如何帮助子类正确调用父类的属性和方法,避免了属性未被继承的问题。

Python3

super().init()含义(单继承,即只有一个父类)

传送门

测试一

我们尝试下面代码,没有super().__init__()时调用A的父类Root的属性和方法(方法里不对Root数据进行二次操作)

class Root(object):
    def __init__(self):
        self.x= '这是属性'        
    def fun(self):
    	#print(self.x)
        print('这是方法')        
class A(Root):
   	def __init__(self):
        print('实例化时执行')
test = A()		#实例化类
test.fun()	#调用方法
test.x		#调用属性

下面是结果:

Traceback (most recent call last):
实例化时执行
这是方法
AttributeError: 'A' object has no attribute 'x'

可以看到此时父类的方法继承成功,可以使用,但是父类的属性却未继承,并不能用

测试二

我们尝试下面代码,没有super().__init__()时调用A的父类Root的属性和方法(方法里对Root数据进行二次操作)

class Root(object):
    def __init__(self):
        self.x= '这是属性'

    def fun(self):
    	print(self.x)
        print('这是方法')
        
class A(Root):
    def __init__(self):
        print('实例化时执行')

test = A()		#实例化类
test.fun()	#调用方法
test.x		#调用属性
Traceback (most recent call last):
AttributeError: 'A' object has no attribute 'x'

可以看到此时报错和测试一相似,果然,还是不能用父类的属性

测试三

我们尝试下面代码,加入==super(=).init()==时调用A的父类Root的属性和方法(方法里对Root数据进行二次操作)

class Root(object):
    def __init__(self):
        self.x = '这是属性'

    def fun(self):
        print(self.x)
        print('这是方法')


class A(Root):
    def __init__(self):
        super().__init__()
        print('实例化时执行')


test = A()  # 实例化类
test.fun()  # 调用方法
test.x  # 调用属性

结果输出如下

实例化时执行
这是属性
这是方法
"这是属性"

此时A已经成功继承了父类的属性,所以super().__init__()的作用也就显而易见了,就是执行父类的构造函数,使得我们能够调用父类的属性

上面是单继承情况,我们也会遇到多继承情况,用法类似,但是相比另一种Root.__init__(self),在继承时会跳过重复继承,节省了资源。

还有很多关于super的用法可以参考
super的使用

<think>我们正在讨论Python中的`__init__`方法和`super().__init__()`的作用。根据用户提供的引用,我们可以总结如下: 1. **`__init__`方法**:这是Python中的初始化方法,用于初始化新创建的对象。当创建一个类的新实例时,`__init__`方法会被自动调用。它负责设置对象的初始状态,例如给对象属性赋值等。注意,`__init__`并不是构造函数(构造函数是`__new__`),它是在对象被创建之后进行初始化的方法[^1]。 2. **`super().__init__()`**:在继承的情况下,子类通常会重写`__init__`方法以添加自己的初始化逻辑。但是,为了确保父类的初始化逻辑也被执行,我们需要在子类的`__init__`方法中调用父类的`__init__`方法。使用`super().__init__()`可以调用父类的初始化方法。这样做的好处是: - 避免显式指定父类名称,使代码更易维护(尤其是在多重继承中)。 - 确保父类的初始化代码得到执行,从而正确初始化继承自父类的属性[^3]。 此外,引用[2]提到了另一个特殊方法`__init_subclass__`,它用于在子类定义时执行一些操作,但这与我们的问题不直接相关。 现在,结合用户之前的问题(关于`__init__`和`super().__init__`)和提供的引用,我们来组织回答: ### 1. `__init__`方法的作用 - `__init__`是类的初始化方法,在创建类的实例时自动调用。 - 它用于初始化实例的属性(即设置实例的初始状态)。 - 它接受至少一个参数`self`(指向实例本身),以及其他的初始化参数。 - 示例: ```python class MyClass: def __init__(self, value): self.value = value # 初始化实例属性 ``` ### 2. `super().__init__()`的作用 - 在继承体系中,子类通过`super().__init__()`调用父类的初始化方法。 - 这样做可以确保父类的初始化逻辑被执行,从而正确初始化从父类继承的属性。 - 如果不调用`super().__init__()`,则父类的初始化代码不会执行,可能导致子类实例缺少父类的属性,进而引发错误。 - 示例: ```python class Parent: def __init__(self, name): self.name = name class Child(Parent): def __init__(self, name, age): super().__init__(name) # 调用父类的__init__方法,初始化name self.age = age # 子类自己的初始化 ``` ### 3. 为什么使用`super()`而不用父类名? - 使用`super()`可以避免硬编码父类名称,这在多重继承中尤为重要,因为它按照方法解析顺序(MRO)来调用父类的方法。 - 如果直接使用父类名(如`Parent.__init__(self, name)`),在多重继承时可能导致某些父类的初始化被重复调用或遗漏。 ### 4. 注意事项 - 在子类的`__init__`方法中,`super().__init__()`的调用通常放在子类初始化代码之前,但这并不是强制的。具体顺序取决于业务逻辑(例如,如果子类的初始化需要依赖父类初始化的结果,则必须先调用父类的初始化)。 - 如果父类没有定义`__init__`方法,或者父类的`__init__`不需要参数,那么子类可以不调用`super().__init__()`,因为Python会隐式调用(如果父类是`object`,则其`__init__`不需要参数)。 ### 示例代码 ```python class Parent: def __init__(self, parent_param): self.parent_attr = parent_param class Child(Parent): def __init__(self, parent_param, child_param): super().__init__(parent_param) # 初始化父类部分 self.child_attr = child_param # 初始化子类部分 # 创建Child实例 obj = Child("parent_value", "child_value") print(obj.parent_attr) # 输出: parent_value print(obj.child_attr) # 输出: child_value ``` ### 总结 - `__init__`:用于初始化对象实例,设置实例属性。 - `super().__init__()`:在继承中确保父类的初始化逻辑被执行,维护继承链的完整性。 §§相关问题§§ 1. 在多重继承中,`super().__init__()`是如何工作的? 2. 如果不调用`super().__init__()`,会有什么后果? 3. `__init__`和`__new__`有什么区别? 4. 如何控制多个父类的初始化顺序?</think>### Python中`__init__`方法和`super().__init__()`的作用详解 #### 1. **`__init__`方法的核心作用** `__init__`是Python类的**初始化方法**(非构造函数),在对象创建后自动调用,用于设置对象的初始状态: - **初始化实例属性**:为对象添加属性并赋初值 - **接收初始化参数**:通过参数定制对象初始状态 - **自动触发**:当使用`类名()`创建实例时自动执行 - **返回值**:必须返回`None`(Python隐式处理) ```python class Person: def __init__(self, name, age): # 初始化方法 self.name = name # 初始化属性 self.age = age # 初始化属性 p = Person("Alice", 30) # 创建实例时自动调用__init__ print(p.name) # 输出: Alice ``` > 注意:`__init__`不是构造函数,真正的构造函数是`__new__`,负责创建实例对象[^1]。 #### 2. **`super().__init__()`的核心作用** 在继承结构中,用于**显式调用父类的初始化方法**: - **维护继承链**:确保父类的初始化逻辑被执行 - **避免属性丢失**:防止父类属性未初始化导致`AttributeError` - **支持多继承**:按MRO(方法解析顺序)自动选择父类 - **参数传递**:将子类接收的参数传递给父类 ```python class Animal: def __init__(self, species): self.species = species # 父类属性初始化 class Dog(Animal): def __init__(self, name, breed): super().__init__("Canine") # 调用父类初始化 self.name = name # 子类特有属性 self.breed = breed # 子类特有属性 dog = Dog("Buddy", "Golden Retriever") print(dog.species) # 输出: Canine (来自父类) print(dog.name) # 输出: Buddy (来自子类) ``` 若不调用`super().__init__()`,父类属性将丢失: ```python # 错误示例:未调用super().__init__() class Cat(Animal): def __init__(self, name): # 缺失super().__init__调用 self.name = name cat = Cat("Whiskers") print(cat.species) # AttributeError: 'Cat'对象没有'species'属性 ``` #### 3. **关键差异与最佳实践** | 特性 | `__init__` | `super().__init__()` | |---------------------|-------------------------------------|------------------------------------| | **调用场景** | 所有类初始化 | 仅用于继承场景 | | **执行必要性** | 必须存在(可空实现) | 父类有初始化逻辑时必须调用 | | **多继承处理** | 无特殊处理 | 按MRO顺序自动选择父类[^3] | | **典型位置** | 类内部定义 | 子类`__init__`的首行或逻辑位置 | **最佳实践**: 1. 在子类`__init__`中**优先调用**`super().__init__()` 2. 多继承时依赖`super()`的MRO机制,避免直接指定父类名 3. 父类参数通过`super().__init__(params)`传递 4. 子类特有初始化放在`super()`调用之后 #### 4. **高级用法:`__init_subclass__`** Python 3.6+ 引入的类装饰器替代方案,在子类定义时触发: ```python class Base: def __init_subclass__(cls, **kwargs): print(f"子类 {cls.__name__} 被定义,参数: {kwargs}") class Child(Base, param=123): # 定义时触发 pass # 输出: 子类 Child 被定义,参数: {'param': 123} [^2] ``` > 提示:`__init_subclass__`常用于框架开发,普通业务代码更常用`super().__init__()`[^2]。
评论 7
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值