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不支持旧样式的类,所以上面提到的任何一种形式都会产生新样式的类。
推荐文章
- Python glob多个文件类型
- 如何可靠地打开与当前运行脚本在同一目录下的文件
- Python csv字符串到数组
- 如何将类标记为已弃用?
- 如何在Python中进行热编码?
- 如何嵌入HTML到IPython输出?
- 在Python生成器上使用“send”函数的目的是什么?
- 是否可以将已编译的.pyc文件反编译为.py文件?
- Django模型表单对象的自动创建日期
- 在Python中包装长行
- 如何计算两个时间串之间的时间间隔
- 我如何才能找到一个Python函数的参数的数量?
- getter和setter是糟糕的设计吗?相互矛盾的建议
- 您可以使用生成器函数来做什么?
- 将Python诗歌与Docker集成