Python 类继承,__bases__, __mro__, super

本文介绍了Python中的类继承概念,包括如何使用__bases__查看基类,利用__mro__理解方法解析顺序,以及如何通过super调用父类方法。通过实例展示了多态性和super的使用,解释了在基类构造函数中调用被覆盖方法的行为。

Python是面向对象的编程语言,也支持类继承。

>>> class Base:

... pass

...

>>> class Derived(Base):

... pass

  

这样就定义了两个类,Derived继承了Base。issubclass(a,b)可以测试继承关系:

>>> issubclass(Derived, Base)

True

  

在Python中,每个类有一个__bases__属性,列出其基类

>>> Derived.__bases__

(<class '__main__.Base'>,)

  

同C++,Python支持多重继承

>>> class Derived2(Derived,Base):

... pass

...

Derived2继承了Derived和Base(实际中不会这么写)

>>> Derived2.__bases__

(<class '__main__.Derived'>, <class '__main__.Base'>)

  

这里,Derived,和Base的顺序不能搞反

>>> class Derived2(Base, Derived):

... pass

...

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

TypeError: Cannot create a consistent method resolution

order (MRO) for bases Derived, Base

  

插一段C++

C++代码

class Base{

};

  

class Derived: public Base{

};

  

class Derived2: public Base, public Derived{

};

  

int main(){

}

mulit_inherit.cc:7:7: warning: direct base 'Base' inaccessible in 'Derived2' due to ambiguity [enabled by default]

class Derived2: public Base, public Derived{

^

mulit_inherit.cc:7:7: warning: direct base 'Base' inaccessible in 'Derived2' due to ambiguity [enabled by default]

class Derived2: public Derived, public Base{

^

可以见,C++并没有限制书写顺序。warning指示了Derrived2中不能访问Base

Derived2 d;

Base &b = d;

error: 'Base' is an ambiguous base of 'Derived2'

Base &b = d;

^

  

回到Python继承,Derived2是Derived的子类,也是Base的子类

>>> issubclass(Derived2, Base)

True

>>> issubclass(Derived2, Derived)

True

  

__bases__类似于Javascript中Object对象的__proto__,是实现继承的基础,不同在于:__bases__不可修改,而且__bases__是类的属性而不是对象属性(Javascript是基于对象的语言);

  

>>> d = Derived2()

>>> d.__bases__

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

AttributeError: 'Derived2' object has no attribute '__bases__'

>>> d.__class__

<class '__main__.Derived2'>

>>> d.__class__.__bases__

(<class '__main__.Derived'>, <class '__main__.Base'>)

  

对象的__class__属性指明了所属类型;

>>> [].__class__

<class 'list'>

>>> ().__class__

<class 'tuple'>

>>> 1.__class__

File "<stdin>", line 1

1.__class__

^

SyntaxError: invalid syntax

  

>>> type(1)

<class 'int'>

在Python中1,是对象还是基本类型?

  

__mro__

__mro__给出了method resolution order,即解析方法调用的顺序

  

>>> Derived.__mro__

(<class '__main__.Derived'>, <class '__main__.Base'>, <class 'object'>)

>>> Derived2.__mro__

(<class '__main__.Derived2'>, <class '__main__.Derived'>, <class '__main__.Base'>, <class 'object'>)

  

看上去和__bases__相像,只是最后面多了个<class 'object'>

  

super

super函数可以用于调用父类的方法,而后者可能被子类覆盖;类似在java中的作用,但使用起来更复杂些。

>>> class Base:

... pass

...

>>> class Derived(Base):

... pass

...

>>> class Derived2(Derived)

File "<stdin>", line 1

class Derived2(Derived)

^

SyntaxError: invalid syntax

>>> class Derived2(Derived):

... pass

...

>>> d = Derived2()

>>> super(Derived2, d)

<super: <class 'Derived2'>, <Derived2 object>>

>>> super(Derived, d)

<super: <class 'Derived'>, <Derived2 object>>

>>> super(Base, d)

<super: <class 'Base'>, <Derived2 object>>

  

参考https://docs.python.org/2/library/functions.html#super

super(type[, object-or-type])

Return a proxy object that delegates method calls to a parent or sibling class of type. This is useful for accessing inherited methods that have been overridden in a class. The search order is same as that used by getattr() except that the type itself is skipped.

  

The __mro__ attribute of the type lists the method resolution search order used by both getattr() and super().

  

>>> isinstance(super(Base, d), Base)

False

>>> isinstance(super(Derived, d), Base)

False

代理对象并不是类层次中某个类的实例!

  

结合多重继承来理解下__mro__和super

class A:

def __init__(self):

print('enter __init__@A')

super(A,self).__init__()

print('exit __init__@A')

class B(A):

def __init__(self):

print('enter __init__@B')

super(B,self).__init__()

print('exit __init__@B')

class C(A):

def __init__(self):

print('enter __init__@C')

super(C,self).__init__()

print('exit __init__@C')

class D(A):

def __init__(self):

print('enter __init__@D')

super(D,self).__init__()

print('exit __init__@D')

class E(B,C):

def __init__(self):

print('enter __init__@E')

super(E,self).__init__()

print('exit __init__@E')

class F(E,D):

def __init__(self):

print('enter __init__@F')

super(F,self).__init__()

print('exit __init__@F')

  

if __name__ == '__main__':

A()

print(A.__mro__)        

B()

print(B.__mro__)        

C()

print(C.__mro__)        

D()

print(D.__mro__)        

E()

print(E.__mro__)        

F()

print(F.__mro__)

运行结果

enter __init__@A

exit __init__@A

(<class '__main__.A'>, <class 'object'>)

enter __init__@B

enter __init__@A

exit __init__@A

exit __init__@B

(<class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

enter __init__@C

enter __init__@A

exit __init__@A

exit __init__@C

(<class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

enter __init__@D

enter __init__@A

exit __init__@A

exit __init__@D

(<class '__main__.D'>, <class '__main__.A'>, <class 'object'>)

enter __init__@E

enter __init__@B

enter __init__@C

enter __init__@A

exit __init__@A

exit __init__@C

exit __init__@B

exit __init__@E

(<class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

enter __init__@F

enter __init__@E

enter __init__@B

enter __init__@C

enter __init__@D

enter __init__@A

exit __init__@A

exit __init__@D

exit __init__@C

exit __init__@B

exit __init__@E

exit __init__@F

(<class '__main__.F'>, <class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>)

观察到,super的执行路径和类的__mro__列举的类顺序吻合;而__mro__的顺序可以看作是深搜的结果

A

/ | \

B C D

\ / /

E /

\ /

F

class E(B, C)中,B和C不是基-派生类关系,E.__mro__中B在C之前,需要注意;

  

多态

  

>>> class Base:

... def sayHello(self):

... print("Base says hello")

...

>>> class Derived(Base):

... pass

...

>>> d = Derived()

>>> d.sayHello()

Base says hello

Derived重写sayHello

>>> class Derived(Base):

... def sayHello(self):

... print("Derived says hello");

...

>>> d = Derived()

>>> d.sayHello()

Derived says hello

  

与参数默认值结合(联想起了C++)

>>> class Base:

... def sayHello(self, str="Base"):

... print("Base says: " + str)

...

>>> class Derived(Base):

... def sayHello(self, str="Derived"):

... print("Dervied says: " + str)

...

>>>

>>> d = Derived()

>>> d.sayHello()

Dervied says: Derived

>>> Base.sayHello(d)

Base says: Base

>>> super(Derived, d).sayHello()

Base says: Base

  

看一下,在基类构造函数中调用被覆盖方法的行为

>>> class Base:

... def sayHello(self):

... str = self.getStr()

... print("Base says: " + str)

... def getStr(self):

... return "Base"

...

>>> class Derived(Base):

... def getStr(self):

... return "Derived"

...

>>>

>>> d = Derived()

>>> d.sayHello()

Base says: Derived

>>> def Base_init(self):

... self.sayHello()

...

>>> Base.__init__ = Base_init

>>> d = Derived()

Base says: Derived

可见,行为类似Java,调用了子类的覆盖方法;

  

<think>我们正在讨论Python中的self.__class__属性。根据用户的问题,他想要理解self.__class__的含义和用法。同时,用户提供了几个引用,我们可以参考这些引用中的信息来辅助回答。首先,我们来理解self.__class__:在Python中,self通常表示的一个实例。self.__class__则是指向该实例所属的对象。也就是说,通过self.__class__,我们可以访问到创建该实例的。引用[1]中提到了一个元autosuper的例子,其中在元的__init__方法中操作了cls(即对象)。虽然这个例子没有直接使用self.__class__,但它展示了级别的操作,这有助于我们理解对象的概念。 引用[2]提到Python默认使用字典来存储对象的实例属性。这让我们知道实例属性存储的方式,而self.__class__则指向该实例的本身也有自己的属性和方法。引用[3]展示了使用vars()函数来查看对象的属性字典。我们可以通过self.__class__来获取,然后也可以使用vars()查看的属性。 引用[4]是一些Python小知识,与当前问题关联不大。现在,我们详细解释self.__class__:1.含义:self.__class__返回实例self所属的。例如:```pythonclass MyClass:passobj =MyClass()print(obj.__class__)#输出:<class '__main__.MyClass'>``` 2.用法:-动态创建同型的新实例:可以使用self.__class__()来创建与当前实例相同型的新实例。-在继承中,即使子覆盖了方法,通过self.__class__仍然可以调用到子的方法,而不是父的方法。这可以实现多态。-在元编程中,有时需要操作对象。3.与type(self)的区别:在普通情况下,type(self)和self.__class__是等价的。但是,如果中定义了__class__属性,那么self.__class__可能会被覆盖(虽然这种情况很少见)。而type(self)总是返回实例的真实型。4.示例:```pythonclass Parent:def create_new(self):#创建一个与self相同型的新实例return self.__class__()classChild(Parent):passp =Parent()c= Child()print(p.create_new().__class__)#输出:<class'__main__.Parent'>print(c.create_new().__class__)#输出:<class '__main__.Child'>```在这个例子中,Parent中的create_new方法使用self.__class__来创建新实例。当通过子Child的实例调用时,它会创建Child的实例,而不是Parent的实例。这体现了多态性。 5.注意事项:-在元中,cls.__class__指向的是元(因为是由元创建的)。-在Python中,也是对象,它们是元的实例。因此,对于一个对象,它的__class__属性指向其元。 6.引用[1]中的元例子与self.__class__的关系:在引用[1]中,元autosuper在创建时,会为设置一个属性(例如`_MyClass__super`),该属性是一个super对象。在实例方法中,我们可以通过`self.__class__`来访问这个属性,例如`self.__class__._MyClass__super`(注意,由于名称重整,实际访问方式可能不同)。 7.在继承链中的行为:由于self.__class__指向的是实例的实际型,即使在父的方法中,self.__class__也是子(如果实例是子的实例)。这样,父的方法可以创建子的实例。8.与super()结合使用:有时我们使用super()来调用父的方法,而super()的第一个参数通常是当前实例的(即self.__class__)。但是要注意,在多重继承中,使用self.__class__作为super的第一个参数可能会导致无限循环(因为self.__class__是子,而super会沿着MRO查找,如果子的方法又调用了父的方法,可能形成循环)。因此,通常建议在方法中使用super()时,显式传递当前名(而不是使用self.__class__)以避免问题。 9.动态改变实例的:虽然不常见,但Python允许改变一个实例的,通过赋值给self.__class__。例如:```pythonclass A:def method(self):print("A")classB:defmethod(self):print("B")a= A()a.method()#输出:Aa.__class__ =Ba.method()#输出:B```注意:这样做需要两个具有相似的内存布局(比如相同的属性),否则可能导致错误。10.总结:self.__class__提供了在实例方法中访问实例所属的能力,使得代码可以动态地根据实际型进行操作,支持多态和动态创建对象。 根据以上内容,我们组织回答。同时,按照要求,我们需要在回答末尾生成相关问题。</think>### Python 中 `self.__class__` 的含义与用法详解 `self.__class__` 是 Python 面向对象编程中的核心属性,表示**当前实例所属的对象**。它提供了在实例方法中动态访问级别的属性和方法的途径,是实现多态和元编程的关键机制。 #### 核心特性解析 1. **动态访问对象** `self.__class__` 返回实例的对象引用,等价于 `type(self)`: ```python class MyClass: def show_class(self): print(self.__class__) # 输出 <class '__main__.MyClass'> obj = MyClass() obj.show_class() ``` 2. **实现动态型创建** 可在运行时创建与当前实例同型的新对象: ```python class Vehicle: def clone(self): return self.__class__() # 创建同型新实例 class Car(Vehicle): pass car = Car() clone = car.clone() # 返回 Car 实例而非 Vehicle 实例 print(type(clone)) # 输出 <class '__main__.Car'> ``` 3. **名称重整(Name Mangling)机制** 双下划线前缀触发 Python 的名称重整规则: ```python class Test: def __init__(self): print(self.__class__.__name__) # 输出 "Test" t = Test() # 实际访问的是重整后的属性名 print(t._Test__class__) # 等价于 t.__class__ ``` 名称重整格式为 `_ClassName__attribute`,避免子属性冲突[^1]。 4. **与元(Metaclass)的交互** 在元编程中,`cls` 参数本质是 `__class__` 的级别等价物: ```python class Meta(type): def __init__(cls, name, bases, attrs): super().__init__(name, bases, attrs) cls.custom_attr = 42 # 动态添加属性 class MyClass(metaclass=Meta): def access_meta(self): print(self.__class__.custom_attr) # 通过实例访问元添加的属性 obj = MyClass() obj.access_meta() # 输出 42 ``` #### 典型应用场景 1. **工厂模式实现** 动态创建当前的子实例: ```python class Animal: def create_child(self, name): child = self.__class__(name) # 创建同型子实例 child.parent = self return child class Dog(Animal): pass parent_dog = Dog("Rex") puppy = parent_dog.create_child("Max") # 返回 Dog 实例 ``` 2. **替代 `super()` 的灵活方案** 在多重继承中直接访问层级: ```python class Base: def method(self): print("Base method") class Derived(Base): def method(self): # 直接调用基方法 self.__class__.__bases__[0].method(self) print("Derived method") obj = Derived() obj.method() # 输出: # Base method # Derived method ``` 3. **动态修改实例型** 运行时改变对象的(慎用): ```python class A: def action(self): print("A") class B: def action(self): print("B") obj = A() obj.action() # 输出 "A" obj.__class__ = B # 修改实例型 obj.action() # 输出 "B" ``` #### 注意事项 1. **与 `type(self)` 的区别** - `self.__class__` 可被重写(尽管不常见) - `type(self)` 始终返回真实型 ```python class Test: @property def __class__(self): return str # 重写 __class__ obj = Test() print(obj.__class__) # 输出 <class 'str'> print(type(obj)) # 输出 <class '__main__.Test'> ``` 2. **性能考量** 直接访问属性时,`self.attr` 比 `self.__class__.attr` 更快,因前者优先搜索实例字典[^2]。 3. **继承链中的行为** 在父方法中使用时,`self.__class__` 指向实际子,实现多态: ```python class Parent: def get_class(self): return self.__class__.__name__ class Child(Parent): pass print(Child().get_class()) # 输出 "Child" ``` #### 工作流系统中的实际应用 在引用[1]的元示例中,`__super` 属性的名称重整机制与 `self.__class__` 直接相关。当在工作流系统中访问 `self.__super` 时: ```python class Workflow: def run(self): # 通过名称重整访问元注入的属性 super_obj = getattr(self, f"_{self.__class__.__name__}__super") super_obj.run_task() ``` [^1]: 展示了名称重整和元如何操作属性 [^2]: 解释了实例属性的存储机制
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值