self = [super init] 为什么要调用

本文探讨了Objective-C初始化方法中的[self=super init]这一常见实践。首先,解释了[super init]用于初始化父类对象的重要性,因为父类的初始化可能会失败并返回nil。其次,指出了即使父类初始化失败,self依然可以继续执行子类的初始化,但使用父类功能可能出错。最后,引用《禅与 Objective-C 编程艺术》说明为何将[super init]的返回值赋给self。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

初始化方法的标准结构是这样子的:

- (instancetype)init
{
    self = [super init]; // call the designated initializer
    if (self) {
        // Custom initialization
    }
    return self;
}

我们主要来看看,这一句:

  self = [super init]; // call the designated initializer

问题1:[super init] 到底做了什么?

问题2:为什么把[super init]的值赋值给self?

问题3:我们用过了 alloc init的两部创建,为什么不是[[super alloc] init]

先来回答问题3,因为这个问题是来搞笑的:

我们看下alloc方法是怎么定义的 
+ (instancetype)alloc;
可以看到alloc是一个类方法,而super不是一个类.

然后我们在来看看问题1:

[super init] 的结果可能有三种:
第一种:  [super init] 初始化成功,这个是最最正常的情况。
第二种:    [super init] 初始化失败,我们都知道oc的两步创建,alloc开辟内存空间,init初始化对象,
但是init还有另外一个作用,在初始化失败的时候,init方法会返回一个nil。
回头行文的最上面,如果selfnil,那么if(self)语句的内容,将不被执行,
已确保程序健壮安全。
- (instancetype)init
{
    self = [super init]; // call the designated initializer
    if (self) {
        // Custom initialization
    }
    return self;
}
第三种:self = [super init]执行之后,内存指向了不相关的地址。这种情况的出现,一般是一下几种情况:
单例、类簇、对象为NSNumber类型、父类在初始化的时候释放了当前对象,
然后重新开辟了新的内存地址。 
self 为什么要赋值为[super init]:”,当程序进入到init这个方法的时候,系统已经生成了对象并分配了存储空间,

在调用[super init]是为了初始化父类对象,在父类对象初始化过程序中有可能失败(如网络资源调用失败)或者返回其它对象(这个取决于你的父类了),
这个时候会返回nil(只解释为nil)。如果父类对象为nil,子类对象其实没必要再执行了。
当然这个时候的self其实也可以继续执行子类对象的初始化工作,因为都是同一个对象,只不过在你调用父类的某一些功能可能不起作用或者报错。

最后,我们来使用《禅与 Objective-C 编程艺术》的原话来回答问题2:

如果你的超类没有成功初始化它自己,你必须假设你在一个矛盾的状态,并且在你的实现中不要处理你自己的初始化逻辑,同时返回 nil。如果你不是这样做,你看你会得到一个不能用的对象,并且它的行为是不可预测的,最终可能会导致你的 app 发生 crash。

一句话概括:

if( self = [super init])这是一种通常的建议写法,赋值并测试nil只是为了防止超类在初始化过程中发生改变,返回了不同的对象。
<think>我们正在讨论Python中`super()`函数和方法解析顺序(MRO)的关系。用户希望理解其调用机制。根据用户提供的引用,我们可以总结如下:1.**`super()`的作用**:在子类中调用父类(或超类)的方法,尤其用于多重继承场景。2.**MRO(方法解析顺序)**:Python通过MRO算法确定在继承链中搜索方法的顺序。MRO采用C3线性化算法,保证子类在父类之前,且同一父类不会被多次搜索(引用[1][2][3])。3.**`super()`的工作原理**:`super()`返回一个代理对象,该对象会根据当前类的MRO顺序查找下一个要调用方法(引用[2][3])。注意,它并不是直接调用父类的方法,而是按照MRO顺序找到下一个匹配的方法。###详细解释####1.MRO的计算与规则Python中每个类都有一个`__mro__`属性,它是一个元组,表示方法解析的顺序,这个顺序由C3算法计算得到。规则包括:-子类优于父类。-多个父类时,按照类定义时的顺序(从左到右)依次检查。-如果一个类在多个父类中出现,只保留第一个(引用[1][3])。例如,在引用[1]中的例子:```pythonclassFather:...classMother:...classChild(Father,Mother):...print(Child.__mro__)#输出:(Child,Father,Mother,object)```调用`Child`实例的`super().method()`时,会首在`Father`中查找`method`,如果`Father`没有,则继续在`Mother`中查找。####2.`super()`的调用机制`super()`有两种使用方式:-**无参数形式**(在Python3中):`super().method(...)`,自动将当前类和实例作为参数传入。-**带参数形式**:`super(type,obj).method(...)`,显式指定从哪个类开始查找(引用[2][5])。**关键点**:-`super()`并不一定调用“父类”方法,而是调用MRO链中当前类的下一个类的方法(引用[2])。-在多重继承中,这可能导致调用的是“兄弟类”的方法或更高级的祖类的方法(引用[2][5])。例如,引用[2]中提到:>使用“super().方法名”调用时,不一定是调用上一层的超类的方法,也可能是超类的超类的方法。####3.`super()`在初始化中的作用在构造函数`__init__`中,常用`super()`来调用父类的初始化方法(引用[1][4][5])。但要注意:-在多重继承中,如果多个父类都有初始化方法,`super()`按照MRO顺序调用,每个类的初始化方法只会被调用一次(引用[5])。例如,引用[5]中的例子:```pythonclassMaster:...classSchool(Master):...classStu(School):defold1_make_cake(self):super().__init__()#调用School的__init__super().make_cake()#调用School的make_cake```####4.`super()`和类属性(实例变量)引用[4]中的例子说明:在子类中通过`super()`调用父类方法时,方法中的`self`仍然是子类的实例。因此,父类方法操作的属性是子类实例的属性(即子类和父类同名的实例变量实际上是同一个变量,除非在父类中重新绑定)。例如:```pythonclassA:defadd(self,m):self.n+=m#这里的self是子类B的实例,所以修改的是B实例的nclassB(A):defadd(self,m):super().add(m)#调用A.add,但此时self是B的实例self.n+=3b=B()b.add(2)#结果b.n变为5(初始3+2+3?但注意初始值在__init__中设置,例子中未完整展示,但原理明确)```###总结-**MRO顺序**由C3算法计算,决定了方法查找的顺序(`__mro__`属性)。-**`super()`**根据当前类的MRO顺序找到下一个类并调用方法,而不是仅仅调用“直接父类”。-使用`super()`可以保证在多重继承中,每个类的方法只被调用一次,且顺序合理。###示例代码以下是一个多重继承的示例,演示`super()`如何按照MRO顺序调用:```pythonclassA:defmethod(self):print("Amethod")classB(A):defmethod(self):print("Bmethod")super().method()#调用下一个类的方法(A.method)classC(A):defmethod(self):print("Cmethod")super().method()#调用下一个类的方法(A.method)classD(B,C):defmethod(self):print("Dmethod")super().method()#调用B.methodd=D()d.method()```输出:```DmethodBmethodCmethodAmethod```这里MRO顺序为:`D->B->C->A->object`。因此,在`B.method`中调用`super().method()`会调用`C.method`,而不是直接调用`A.method`(因为MRO中B的下一个是C)。###注意事项1.当类的继承关系发生变化(如改变父类顺序或增减父类)时,MRO会相应改变,可能导致`super()`的行为变化。2.所有父类方法应保持兼容性(如参数列表一致),否则可能出错。###§§相关问题§§1.Python如何计算MRO(详细说明C3算法)?2.在多重继承中使用`super()`可能产生的问题(如菱形继承问题)及解决方案?3.如何避免`super()`调用时父类方法的重复调用?4.Python中哪些内置函数或模块与继承机制相关?</think> ### Python中`super()`的机制与MRO解析顺序 `super()`函数在Python中用于调用父类方法,其行为核心依赖于**方法解析顺序(Method Resolution Order, MRO)**。以下通过关键机制逐步解析: #### 1. MRO的核心作用 MRO是Python解决多重继承方法冲突的算法(C3线性化算法): - 遵循**单调性原则**:子类优级 > 父类优级 - 保证**局部优级**:类定义中的父类顺序决定查找顺序 - 避免重复调用:每个类在MRO中仅出现一次[^3] ```python class A: pass class B(A): pass class C(A): pass class D(B, C): pass print(D.__mro__) # 输出: (D, B, C, A, object) ``` #### 2. `super()`的工作原理 `super()`不直接调用“父类”,而是按MRO顺序查找**下一个可用方法**[^2]: ```python class Father: def method(self): print("Father的方法") class Mother: def method(self): print("Mother的方法") class Child(Father, Mother): # MRO: Child→Father→Mother def call(self): super().method() # 按MRO调用下一个类Father的方法[^1] Child().call() # 输出: Father的方法 ``` #### 3. 关键特性详解 1. **代理对象机制**: `super()`返回特殊代理对象,动态绑定当前MRO链: ```python class A: def run(self): print("A") class B(A): def run(self): super() # 返回<super: <class 'B'>, <B object>> super().run() # 调用MRO中B的下一个类A.run ``` 2. **构造函数初始化**: 必须显式调用父类`__init__`[^4]: ```python class Person: def __init__(self, name): self.name = name class Employee(Person): def __init__(self, name, id): super().__init__(name) # 初始化父类属性 self.id = id ``` 3. **多继承陷阱**: 菱形继承中`super()`调用可能跨越层级[^5]: ```python class A: def run(self): print("A") class B(A): def run(self): super().run() # 本意调用A,实际可能调用C! class C(A): def run(self): print("C") class D(B, C): pass # MRO: D→B→C→A D().run() # 输出: C ``` #### 4. 使用规范 1. **统一参数形式**: - Python 3+: `super().method(args)` - 显式指定: `super(CurrentClass, self).method(args)` 2. **继承设计原则**: - 避免同名方法语义冲突 - 限制继承深度(建议≤3层) - 优使用组合替代多重继承 #### 5. 常见误区 1. **`super()`调用父类** × 实际调用**MRO顺序中的下一个类** ✓ 2. **初始化顺序错误**: ```python class Child(Parent): def __init__(self): self.child_var = 1 # 错误!应初始化父类 super().__init__() ``` ### 总结图示 ```mermaid graph LR A[子类实例调用super] --> B[获取MRO链] B --> C{查找当前类位置} C -->|定位索引| D[调用下一个类方法] D -->|完成| E[返回结果] D -->|未找到| F[继续向后查找] F -->|到达object| G[抛出AttributeError] ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值