Python新式类与经典类区别,钻石搜索模式

本文详细介绍了Python中从2.2版本引入的新式类与经典类的区别,包括定义方式、继承顺序的变化及__slots__和__getattribute__方法的使用。

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

Python在2.2之后就有使用一种叫做new style class,即新式类

首先需要说明的是,在python3.X(包括3.0)中,新建类都自动生成为新式类,新式类成为默认值。

(如果不是为了兼容性考虑,建议使用最新版本的python解释环境,毕竟发展是朝向更加标准、清晰走的。)

新式类的定义也就是等同于与经典类的区别: 

1. 第一个区别是在声明时有区别,得到的结果也有不同

# 在python2.7解释环境中
class A: pass    #经典类
class B(object): pass	#在2.X环境中,若声明为新式类需要直接继承object类

a = A()
b = B()

print a
print type(a)
print type(a.__class__)

print b
print type(b)
print type(b.__class__)

结果:

<__main__.A instance at 0x000001B34B1707B8>
<type 'instance'>
__main__.A

<__main__.B object at 0x000001B34B170278>
<class '__main__.B'>
<class '__main__.B'>

而在3.x环境中直接进行定义即为新式类:

# 在python 3.6解释环境中
class C:pass # 新式类为默认值,无需显式继承自object,等同于在python2.X中的语句: class C(object): pass

c = C()
print(c)
print(c.__class__)
print(type(c))
结果:

<__main__.C object at 0x000001B34B16B400>
<class '__main__.C'>
<class '__main__.C'>

2. 新式类的继承顺序较经典类继承顺序发生改变。

经典类的多继承时,属性搜索顺序为:先深入继承树的左侧,再返回开始找右侧,也就是深度优先;

新式类的多继承时,属性搜索顺序为:先找最近超类(父类)从左至右,再深度搜索更高超类,也就是所谓的广度优先。
例:

# ptyhon 3.6解释环境中,新式类广度优先
class A:    x = 1

class B(A):    pass

class C(A):    x = 3

class D(B,C):    pass

d = D()
print(d.x)
结果:

>>> 3
属性的搜索过程:d --> D --> B --> C --> A,

而如果在经典类搜索模式中以上搜索过程就变为:d --> D --> B --> A --> C

# ptyhon 2.7解释环境中,新式类广度优先
class A:    x = 1

class B(A):    pass

class C(A):    x = 3

class D(B,C):    pass

d = D()
print(d.x)

结果:

>>> 1
在经典类中,有一个概念就是钻石搜索模式,所谓的钻石搜索模式就是经典类搜索模式,即上面提到的深度优先原则搜索模式,在看《python学习手册(第四版)》时有一点混乱,所以这里拿出来说一下。


3. 支持__slots__实例属性列表

__slots__中加入的属性是该类生成的实例能够访问和改变的唯一属性(包括从超类__slots__中获得的属性)

# python3.6解释环境,windows系统下
class D:
    __slots__ = ['name','age']
    
d = D()
d.name = 'Dogg Snop'
print(d.name)

d.location = 'Tianjing'
print(d.location)
结果:

Dogg Snop
Traceback (most recent call last):
  File "<pyshell#108>", line 1, in <module>
    d.location = 'Tianjing'
AttributeError: 'D' object has no attribute 'location'
如果属性没有在类的命名空间中使用__slots__指出,那么实例就无法再外部进行赋值使用(即添加新属性)
但是可以使用类名直接进行类属性添加:

D.location = "Tianjing"
print(d.location)
结果:

Tianjing
这个也就是在实例中去掉了__dict__属性,才出现无法再实例中无法添加新属性,但是类名直接添加属性;如果想要让用户添加属性,但是又不想被滥用,则可以在__slots__中添加__dict__属性: __slots__ = [……, '__dict__'],这样用户就无法直接使用d.attrname = attrvalue,而必须使用d.__slots__.__dict__[attrname] = attrvalue,防止意外添加属性导致的属性错误和泛滥。

4. 在新式类中,添加了__getattribute__()方法

# Python3.X解释器中
class A:
    def __getattribute__(self, *args, **kwargs):
        print "A.__getattribute__"  
a = A()
a.test
结果:

>>> A.__getattribute__


# Python 2.X解释器中 
class B:    
    def __getattribute__(self, *args, **kwargs):    
        print "B.__getattribute__"
b = B()
b.test

结果:

Traceback (most recent call last):
  File "<pyshell#109>", line 1, in <module>
    b.test
AttributeError: B instance has no attribute 'test'

总结:新式类和经典类是在Python3.0出现以后产生的一种类的新形势,而在2.X版本中添加新式类的定义形式,主要目的还是为了达到兼容性;如果是最初学习的小白,建议直接使用3.X版本的解释器,毕竟越新越规范。





### Python 新式经典区别 #### 型定义差异 在 Python 2 中,如果一个未显式继承 `object`,它会被视为经典;反之,则为新式。而在 Python 3 中,所有默认继承自 `object`,因此不存在经典的概念[^1]。 #### 方法解析顺序 (MRO) 新式采用 C3 线性化算法来决定方法解析顺序 (Method Resolution Order),这种方法确保每个父只被访问一次,并维持正确的继承层次结构。相比之下,经典使用深度优先搜索的方式解析方法,可能导致复杂多重继承场景下的不可预期行为[^5]。 #### 构造函数机制 对于新式而言,存在两个重要的特殊方法:`__new__` 和 `__init__`。其中 `__new__` 是用于创建实例的静态方法,而 `__init__` 负责初始化已创建的对象。这一区分赋予了开发者更大的灵活性。然而,在经典中仅提供 `__init__` 方法而不支持 `__new__`[^5]。 #### 内置属性方法增强 新式引入了一些有用的内置特性,例如可以通过设置 `__slots__` 来限制对象能够动态添加哪些属性,以及利用 `super()` 函数简化对父方法的调用过程。这些功能在经典里要么缺失要么不够完善[^5]。 #### 使用场景分析 由于上述优势所在,在现代编程实践中几乎总是建议选用新式而非经典。特别是在涉及多重继承、需要精确控制对象生命周期或者希望充分利用 Python 提供的各种高级 OOP 特性的场合下更是如此。需要注意的是,随着 Python 3 成为主流版本号之后,讨论经典的实际意义已经大大降低,因为后者完全被淘汰掉了[^4]。 ```python class NewStyleClass(object): """A new-style class example.""" def __init__(self, value): self.value = value def show_value(self): print(f"The value is {self.value}") # In Python 3+, all classes are implicitly new-style. class ImplicitNewStyleClass: pass ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值