协慌网

登录 贡献 社区

Python 中的旧样式和新样式类有什么区别?

Python 中的旧样式和新样式类有什么区别?我什么时候应该使用其中一种?

答案

来自http://docs.python.org/2/reference/datamodel.html#new-style-and-classic-classes

在 Python 2.1 中,旧式类是用户可用的唯一风格。

(旧式)类的概念与类型的概念无关:如果x是旧式类的实例,则x.__class__指定x的类,但type(x)始终是<type 'instance'>

这反映了这样一个事实,即所有旧式实例独立于其类,都使用一个称为实例的内置类型实现。

Python 2.2 中引入了新式类,以统一类和类型的概念 。新式类只是用户定义的类型,不多也不少。

如果 x 是新样式类的实例,则type(x)通常与x.__class__相同(虽然这不能保证 - 允许新样式类实例覆盖为x.__class__返回的值) 。

引入新式类的主要动机是提供具有完整元模型的统一对象模型

它还具有许多直接的好处,例如能够对大多数内置类型进行子类化,或引入 “描述符”,从而启用计算属性。

出于兼容性原因,默认情况下类仍为旧式

通过将另一个新样式类(即类型)指定为父类来创建新样式类,或者如果不需要其他父类,则创建 “顶级类型” 对象。

除了返回的类型之外,新样式类的行为在许多重要细节中与旧样式类的行为不同。

其中一些更改是新对象模型的基础,就像调用特殊方法的方式一样。其他是针对兼容性问题之前无法实现的 “修复”,例如在多重继承的情况下的方法解析顺序。

Python 3 只有新式的类

无论你是否从object继承,类都是 Python 3 中的新风格。

宣言明智的:

新式类继承自 object 或其他新式类。

class NewStyleClass(object):
    pass

class AnotherNewStyleClass(NewStyleClass):
    pass

旧式的课程没有。

class OldStyleClass():
    pass

旧样式类和新样式类之间的重要行为更改

  • 超级补充
  • MRO 改变了(下面解释)
  • 描述符添加
  • 除非从Exception派生,否则无法引发新样式类对象(下面的示例)
  • __slots__补充道

MRO(方法解决顺序)已更改

在其他答案中提到过,但这里是经典 MRO 和 C3 MRO(用于新风格类别)之间差异的具体例子。

问题是在多重继承中搜索属性(包括方法和成员变量)的顺序。

经典课程从左到右进行深度优先搜索。第一场比赛停止。它们没有__mro__属性。

class C: i = 0
class C1(C): pass
class C2(C): i = 2
class C12(C1, C2): pass
class C21(C2, C1): pass

assert C12().i == 0
assert C21().i == 2

try:
    C12.__mro__
except AttributeError:
    pass
else:
    assert False

新式 MRO 在单个英语句子中合成更复杂。 这里将详细解释。它的一个属性是 Base 类只在其所有 Derived 类都被搜索过。它们具有__mro__属性,显示搜索顺序。

class C(object): i = 0
class C1(C): pass
class C2(C): i = 2
class C12(C1, C2): pass
class C21(C2, C1): pass

assert C12().i == 2
assert C21().i == 2

assert C12.__mro__ == (C12, C1, C2, C, object)
assert C21.__mro__ == (C21, C2, C1, C, object)

除非从Exception派生,否则无法引发新样式类对象

围绕 Python 2.5,可以引发许多类,围绕 Python 2.6,这被删除了。在 Python 2.7.3 上:

# OK, old:
class Old: pass
try:
    raise Old()
except Old:
    pass
else:
    assert False

# TypeError, new not derived from `Exception`.
class New(object): pass
try:
    raise New()
except TypeError:
    pass
else:
    assert False

# OK, derived from `Exception`.
class New(Exception): pass
try:
    raise New()
except New:
    pass
else:
    assert False

# `'str'` is a new style object, so you can't raise it:
try:
    raise 'str'
except TypeError:
    pass
else:
    assert False