Python中的旧样式和新样式类有什么区别?我什么时候应该使用其中一种?
答案 0 :(得分:519)
来自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__
相同(尽管不能保证 - a 允许新式类实例覆盖返回的值x.__class__
)。引入新式类的主要动机是提供具有完整元模型的统一对象模型。
它还有许多直接的好处,比如能力 子类大多数内置类型,或引入“描述符”, 它启用了计算属性。
出于兼容性原因,默认情况下类仍为旧式。
通过指定另一个新样式类来创建新样式类 (即类型)作为父类,如果不是,则为“顶级类型”对象 需要其他父母。
新式课程的行为与旧式课程的行为不同 除了什么类型之外,还有一些重要的细节类 回报。
其中一些变化是新对象模型的基础,例如 调用特殊方法的方式。其他人是“修复”,不能 之前要实现兼容性问题,比如方法 多重继承时的解析顺序。
Python 3只有新式的类。
无论你是否从
object
继承,类都是新式的 在Python 3中。
答案 1 :(得分:288)
<强>宣言明智:强>
新式类继承自object或其他新式类。
class NewStyleClass(object):
pass
class AnotherNewStyleClass(NewStyleClass):
pass
旧式课没有。
class OldStyleClass():
pass
答案 2 :(得分:211)
旧样式和新样式类之间的重要行为更改
Exception
(下面的示例)__slots__
已添加在其他答案中提到过,但这里是经典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在单个英语句子中合成更复杂。详细解释here。它的一个属性是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
答案 3 :(得分:36)
对于属性查找,旧样式类仍然稍微快一些。这通常不重要,但在性能敏感的Python 2.x代码中可能很有用:
In [3]: class A: ...: def __init__(self): ...: self.a = 'hi there' ...: In [4]: class B(object): ...: def __init__(self): ...: self.a = 'hi there' ...: In [6]: aobj = A() In [7]: bobj = B() In [8]: %timeit aobj.a 10000000 loops, best of 3: 78.7 ns per loop In [10]: %timeit bobj.a 10000000 loops, best of 3: 86.9 ns per loop
答案 4 :(得分:32)
Guido编写了The Inside Story on New-Style Classes,这是一篇关于Python中新风格和旧式类的精彩文章。
Python 3只有新式的类,即使你写了一个“旧式类”,它也是隐式派生自object
。
新式课程有一些缺乏旧式课程的高级功能,例如super
和新的C3 mro,一些神奇的方法等。
答案 5 :(得分:21)
这是一个非常实用的,真/假的差异。以下代码的两个版本之间的唯一区别是,在第二个版本中Person继承自object。除此之外,两个版本相同,但结果不同:
1)旧式课程
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>
>>>
2)新式课程
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>
>>>
答案 6 :(得分:7)
新式类继承自object
,必须在Python 2.2之后编写(即class Classname(object):
而不是class Classname:
)。核心变化是统一类型和类,其中很好的副作用是它允许你从内置类型继承。
阅读descrintro了解详情。
答案 7 :(得分:5)
新样式类可以使用super(Foo, self)
,其中Foo
是一个类,self
是实例。
super(type[, object-or-type])
返回一个代理对象,该方法将方法调用委托给父类或兄弟类类型。这对于访问已在类中重写的继承方法很有用。搜索顺序与getattr()使用的搜索顺序相同,只是跳过了类型本身。
在Python 3.x中,您只需在没有参数的类中使用super()
。
答案 8 :(得分:4)
或者更确切地说,你应该总是使用新式的类,除非你有代码需要使用早于2.2的Python版本。