Python:python3中__bases__的使用(MRO)

本文详细解析了Python中多重继承的正确实践,特别是__bases__属性的运用,对比了错误与正确的示例,揭示了继承过程中方法与属性的继承特性,并探讨了MRO排序原则。

注:尚未在pyhon2中测试
参考文档:https://fishc.com.cn/forum.php?mod=viewthread&tid=48888&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403

· 错误示例

在这里插入图片描述
——————————————————————————————————
在这里插入图片描述

class A():
    def __init__(self):
        self.a=10
    def get_a(self):
        print("我是a")

class B():
    def __init__(self):
        self.b=10
    def get_b(self):
        print("我是b")

B.__bases__ += (A,)
· 正确用法

在这里插入图片描述

class A():
    def __init__(self):
        self.a=10
    def get_a(self):
        print("我是a")

class Before_B():
    pass
class B(Before_B):
    def __init__(self):
        self.b=10
    def get_b(self):
        print("我是b")

print(B.__bases__)
B.__bases__ += (A,)

在这里插入代码片由此可见,使用__bases__时,不继承__init__里的属性,只继承方法;为B类添加A类方法的前提是B是一个继承类,即B.__bases__为(<class ‘main.B的父类’>,)

· 查看继承的类,MRO

使用 print(类名._mro_) 可查看继承的顺序。
参考文档《一窥Python中MRO排序原理》,可以看出是深度优先的原则。
参考文档《多重继承的陷阱:钻石继承(菱形继承)问题》则写着广度优先。
?????
在这里插入图片描述

<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 &#39;__main__.MyClass&#39;>``` 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&#39;__main__.Parent&#39;>print(c.create_new().__class__)#输出:<class &#39;__main__.Child&#39;>```在这个例子中,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 &#39;__main__.MyClass&#39;> 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 &#39;__main__.Car&#39;> ``` 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 &#39;str&#39;> print(type(obj)) # 输出 <class &#39;__main__.Test&#39;> ``` 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
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值