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


当前回答

这里有一个非常实际的真/假的区别。以下代码的两个版本之间的唯一区别是,在第二个版本中,Person从object继承。除此之外,这两个版本是相同的,但结果不同:

Old-style classes class Person(): _names_cache = {} def __init__(self,name): self.name = name def __new__(cls,name): return cls._names_cache.setdefault(name,object.__new__(cls,name)) ahmed1 = Person("Ahmed") ahmed2 = Person("Ahmed") print ahmed1 is ahmed2 print ahmed1 print ahmed2 >>> False <__main__.Person instance at 0xb74acf8c> <__main__.Person instance at 0xb74ac6cc> >>> New-style classes class Person(object): _names_cache = {} def __init__(self,name): self.name = name def __new__(cls,name): return cls._names_cache.setdefault(name,object.__new__(cls,name)) ahmed1 = Person("Ahmed") ahmed2 = Person("Ahmed") print ahmed2 is ahmed1 print ahmed1 print ahmed2 >>> True <__main__.Person object at 0xb74ac66c> <__main__.Person object at 0xb74ac66c> >>>

其他回答

新旧样式类之间的重要行为变化

超级补充道 MRO变更(解释如下) 描述符添加 除非派生自Exception,否则不能引发new样式类对象(如下例) __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在一个英语句子中合成起来更加复杂。这里有详细的解释。它的一个属性是只搜索一次基类的所有派生类。它们有__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

New-style类继承自object,并且在Python 2.2以后必须这样编写(即类Classname(object):而不是类Classname:)。核心变化是统一类型和类,这样做的好处是允许从内置类型继承。

更多细节请阅读描述介绍。

这里有一个非常实际的真/假的区别。以下代码的两个版本之间的唯一区别是,在第二个版本中,Person从object继承。除此之外,这两个版本是相同的,但结果不同:

Old-style classes class Person(): _names_cache = {} def __init__(self,name): self.name = name def __new__(cls,name): return cls._names_cache.setdefault(name,object.__new__(cls,name)) ahmed1 = Person("Ahmed") ahmed2 = Person("Ahmed") print ahmed1 is ahmed2 print ahmed1 print ahmed2 >>> False <__main__.Person instance at 0xb74acf8c> <__main__.Person instance at 0xb74ac6cc> >>> New-style classes class Person(object): _names_cache = {} def __init__(self,name): self.name = name def __new__(cls,name): return cls._names_cache.setdefault(name,object.__new__(cls,name)) ahmed1 = Person("Ahmed") ahmed2 = Person("Ahmed") print ahmed2 is ahmed1 print ahmed1 print ahmed2 >>> True <__main__.Person object at 0xb74ac66c> <__main__.Person object at 0xb74ac66c> >>>

新的样式类可以使用super(Foo, self),其中Foo是类,self是实例。

超级(类型、对象或者类型) 返回一个代理对象,该对象将方法调用委托给类型的父类或兄弟类。这对于访问在类中被重写的继承方法非常有用。除了类型本身被跳过之外,搜索顺序与getattr()所使用的相同。

在Python 3中。X你可以简单地在类中使用super()而不带任何参数。

Declaration-wise:

New-style类继承自object或另一个New-style类。

class NewStyleClass(object):
    pass

class AnotherNewStyleClass(NewStyleClass):
    pass

老式的类没有。

class OldStyleClass():
    pass

注意事项:

Python 3不支持旧样式的类,所以上面提到的任何一种形式都会产生新样式的类。