当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《Python中的旧样式和新样式类有什么区别?》经验,为你挑选了8个好方法。

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



1> Mark Cidade..:

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

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

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

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

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

如果x是新样式类的实例,那么type(x)通常是相同的x.__class__(尽管不能保证 - 允许新样式类实例覆盖返回的值x.__class__).

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

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

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

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

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

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

Python 3只有新式的类.

无论你是否是子类object,类都是Python 3中的新风格.


像`super()`这样的某些功能不适用于旧式类.更不用说,正如那篇文章所说,有一些基本的修复,比如MRO和特殊的方法,这不仅仅是使用它的一个很好的理由.
这些差异没有一个听起来像使用新式课程的令人信服的理由,但每个人都说你应该总是使用新式.如果我像我应该使用鸭子打字,我永远不需要使用`type(x)`.如果我不是内置类型的子类,那么我似乎没有看到新式类的任何优势.有一个缺点,就是`(object)`的额外输入.
@User:旧式类在2.7中的行为与在2.1中的行为相同 - 因为很少有人甚至记得这些怪癖,而且文档不再讨论大部分内容,它们甚至更糟.上面的文档引用直接说明:有些"修复"无法在旧式类上实现.除非您想要遇到自Python 2.1以来没有其他人处理过的怪癖,并且文档甚至不再解释,否则不要使用旧式类.
这里有一个例子,如果你在2.7中使用旧式类,你可能会偶然发现:http://bugs.python.org/issue21785
对于任何想知道的人来说,在Python 3中明确继承对象的一个​​很好的理由是它使得支持Python的多个版本变得更容易.
"...在Python 3中.但是建议您仍然从对象中继承子类." 不再是正确的建议:https://docs.python.org/2/reference/datamodel.html#new-style-and-classic-classes
这里有很多理由只使用新式的类.它使事情变得更容易 - 保持语言在概念上简单,减少混淆,增加功能,避免使用旧式类的怪癖,并确保与Python 3的兼容性.

2> Mark Harriso..:

宣言明智的:

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

class NewStyleClass(object):
    pass

class AnotherNewStyleClass(NewStyleClass):
    pass

旧式的课程没有.

class OldStyleClass():
    pass


如果一个新式类继承自另一个新式类,那么通过扩展,它继承自`object`.
@abc我相信``class A:pass``和``class A():pass``是完全等价的.第一种方式_"A不继承任何父类"_,第二种方式_"A继承无父类"_.这非常类似于``not is``和``is is```
正如旁注,对于3.X,"对象"的继承是自动假设的(意味着我们无法在3.X中继承"对象").出于向后兼容的原因,尽管保留"(对象)"也不错.

3> Ciro Santill..:

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

超级补充

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


很清楚总结,谢谢.当你说"难以用英语解释"时,我认为你正在描述一个后序深度优先搜索,而不是使用预先深度优先搜索的旧式类.(预购意味着我们在第一个孩子之前搜索自己,并且延期交货意味着我们在最后一个孩子之后搜索自己).

4> xioxox..:

对于属性查找,旧样式类仍然稍微快一些.这通常不重要,但在对性能敏感的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


将纯Python代码用于性能敏感应用程序可能是一个坏主意.没有人说:"我需要快速代码,所以我将使用旧式的Python类." Numpy不算纯Python.
有趣的是你在实践中注意到,我只是读到这是因为新风格的类,一旦他们在实例dict中找到了属性,就必须进行额外的查找以确定它是否是描述,即它有一个需要调用__get__方法来获取要返回的值.旧样式类简单地返回找到的对象而没有额外的计算(但是后来不支持描述符).您可以在Guido http://python-history.blogspot.co.uk/2010/06/inside-story-on-new-style-classes.html的这篇优秀文章中阅读更多内容,特别是关于__slots__的部分.

5> Xiao Hanyu..:

Guido写了一篇关于New-Style Classes的The Inside Story,这是一篇关于Python中新风格和旧式类的非常棒的文章.

Python 3只有新式的类,即使你写了一个'old-style class',它也是隐式派生的object.

新式类具有一些缺乏旧式类的高级功能,例如super新的C3 mro,一些神奇的方法等.



6> ychaouche..:

这是一个非常实用的,真/假的区别.以下代码的两个版本之间的唯一区别是,在第二个版本中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>
>>>


`_names_cache`是一个字典,用于缓存(存储以备将来检索)你传给`Person .__ new__`的每个名字.setdefault方法(在任何字典中定义)有两个参数:键和值.如果密钥在dict中,它将返回其值.如果它不在dict中,它将首先将其设置为作为第二个参数传递的值,然后返回它.
用法是错误的.这个想法是不构造一个新对象,如果它已经存在,但在你的情况下`__new __()`总是被调用,它总是构造一个新对象,然后抛出它.在这种情况下,`if`优于`.setdefault()`.

7> 小智..:

新样式类继承自objectPython 2.2之后必须编写(即class Classname(object):代替class Classname:).核心变化是统一类型和类,这样做的好处是它允许您从内置类型继承.

阅读descrintro了解更多详情.



8> jamylak..:

新样式类可以使用super(Foo, self)where Foo类和self实例.

super(type[, object-or-type])

返回将方法调用委托给父类或兄弟类类型的代理对象.这对于访问已在类中重写的继承方法很有用.搜索顺序与getattr()使用的搜索顺序相同,只是跳过了类型本身.

在Python 3.x中,您可以简单地super()在没有参数的类中使用.

推荐阅读
小白也坚强_177
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有