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

发布于 2024-07-05 04:07:11 字数 44 浏览 5 评论 0 原文

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

What is the difference between old style and new style classes in Python? When should I use one or the other?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

难得心□动 2024-07-12 04:07:11

来自新式和经典类< /a>

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

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

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

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

如果 x 是新式类的实例,则 type(x) 通常是
x.__class__ 相同(尽管不能保证这一点 –
新式类实例允许覆盖返回值
对于x.__class__)。

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

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

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

新式类是通过指定另一个新式类来创建的
(即类型)作为父类,或者“顶级类型”对象(如果没有)
需要另一位家长。

新式类的行为与旧式类的行为不同
类中除了什么类型还有一些重要的细节
返回。

其中一些更改是新对象模型的基础,例如
调用特殊方法的方式。 其他的是无法修复的“修复”
出于兼容性考虑而之前实现,例如该方法
多重继承情况下的解析顺序。

Python 3 仅具有新式类

无论您是否从 object 子类化,类都是新式的
在 Python 3 中。

From New-style and classic classes:

Up to Python 2.1, old-style classes were the only flavour available to the user.

The concept of (old-style) class is unrelated to the concept of type:
if x is an instance of an old-style class, then x.__class__
designates the class of x, but type(x) is always <type
'instance'>
.

This reflects the fact that all old-style instances, independently of
their class, are implemented with a single built-in type, called
instance.

New-style classes were introduced in Python 2.2 to unify the concepts of class and type.
A new-style class is simply a user-defined type, no more, no less.

If x is an instance of a new-style class, then type(x) is typically
the same as x.__class__ (although this is not guaranteed – a
new-style class instance is permitted to override the value returned
for x.__class__).

The major motivation for introducing new-style classes is to provide a unified object model with a full meta-model.

It also has a number of immediate benefits, like the ability to
subclass most built-in types, or the introduction of "descriptors",
which enable computed properties.

For compatibility reasons, classes are still old-style by default.

New-style classes are created by specifying another new-style class
(i.e. a type) as a parent class, or the "top-level type" object if no
other parent is needed.

The behaviour of new-style classes differs from that of old-style
classes in a number of important details in addition to what type
returns.

Some of these changes are fundamental to the new object model, like
the way special methods are invoked. Others are "fixes" that could not
be implemented before for compatibility concerns, like the method
resolution order in case of multiple inheritance.

Python 3 only has new-style classes.

No matter if you subclass from object or not, classes are new-style
in Python 3.

究竟谁懂我的在乎 2024-07-12 04:07:11

声明方式:

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

class NewStyleClass(object):
    pass

class AnotherNewStyleClass(NewStyleClass):
    pass

旧式课程则不然。

class OldStyleClass():
    pass

Python 3 注意:

Python 3 不支持旧样式类,因此上述任何一种形式都会生成新样式类。

Declaration-wise:

New-style classes inherit from object, or from another new-style class.

class NewStyleClass(object):
    pass

class AnotherNewStyleClass(NewStyleClass):
    pass

Old-style classes don't.

class OldStyleClass():
    pass

Python 3 Note:

Python 3 doesn't support old style classes, so either form noted above results in a new-style class.

孤城病女 2024-07-12 04:07:11

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

  • super 添加了
  • 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 在单个英语句子中综合起来更加复杂。 此处对此进行了详细解释。 它的属性之一是,只有在搜索完基类的所有派生类后,才会搜索基类。 它们具有显示搜索顺序的 __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

Important behavior changes between old and new style classes

  • super added
  • MRO changed (explained below)
  • descriptors added
  • new style class objects cannot be raised unless derived from Exception (example below)
  • __slots__ added

MRO (Method Resolution Order) changed

It was mentioned in other answers, but here goes a concrete example of the difference between classic MRO and C3 MRO (used in new style classes).

The question is the order in which attributes (which include methods and member variables) are searched for in multiple inheritance.

Classic classes do a depth-first search from left to right. Stop on the first match. They do not have the __mro__ attribute.

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

New-style classes MRO is more complicated to synthesize in a single English sentence. It is explained in detail here. One of its properties is that a base class is only searched for once all its derived classes have been. They have the __mro__ attribute which shows the search order.

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)

New style class objects cannot be raised unless derived from Exception

Around Python 2.5 many classes could be raised, and around Python 2.6 this was removed. On 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
╭⌒浅淡时光〆 2024-07-12 04:07:11

旧式类的属性查找速度仍然稍快一些。 这通常并不重要,但在性能敏感的 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

Old style classes are still marginally faster for attribute lookup. This is not usually important, but it may be useful in performance-sensitive Python 2.x code:

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
往事随风而去 2024-07-12 04:07:11

Guido 写了内部故事Story on New-Style Classes,一篇关于 Python 中新式和旧式类的非常好的文章。

Python 3 只有新式类。 即使您编写了一个“旧式类”,它也是隐式地从 object 派生的。

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

Guido has written The Inside Story on New-Style Classes, a really great article about new-style and old-style class in Python.

Python 3 has only new-style class. Even if you write an 'old-style class', it is implicitly derived from object.

New-style classes have some advanced features lacking in old-style classes, such as super, the new C3 mro, some magical methods, etc.

一紙繁鸢 2024-07-12 04:07:11

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

  1. 旧式类

    类 Person(): 
          _names_cache = {} 
          def __init__(自我,名字): 
              self.name = 名字 
          def __new__(cls,名称): 
              返回 cls._names_cache.setdefault(name,object.__new__(cls,name)) 
    
      ahmed1 = 人(“艾哈迈德”) 
      ahmed2 = 人(“艾哈迈德”) 
      打印 ahmed1 是 ahmed2 
      打印艾哈迈德1 
      打印艾哈迈德2 
    
    
      >>>>>   错误的 
      <__main__.Person 实例位于 0xb74acf8c> 
      <__main__.Person 实例位于 0xb74ac6cc> 
      >>>>> 
    
      
  2. 新式类

    类 Person(对象): 
          _names_cache = {} 
          def __init__(自我,名字): 
              self.name = 名字 
          def __new__(cls,名称): 
              返回 cls._names_cache.setdefault(name,object.__new__(cls,name)) 
    
      ahmed1 = 人(“艾哈迈德”) 
      ahmed2 = 人(“艾哈迈德”) 
      打印 ahmed2 是 ahmed1 
      打印艾哈迈德1 
      打印艾哈迈德2 
    
      >>>>>   真的 
      <__main__.Person 对象位于 0xb74ac66c> 
      <__main__.Person 对象位于 0xb74ac66c> 
      >>>>> 
      

Here's a very practical, true/false difference. The only difference between the two versions of the following code is that in the second version Person inherits from object. Other than that, the two versions are identical, but with different results:

  1. 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>
    >>>
    
    
  2. 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>
    >>>
    
猥︴琐丶欲为 2024-07-12 04:07:11

新式类继承自 object,并且在 Python 2.2 及以上版本中必须这样编写(即 class Classname(object): 而不是 class Classname:)。 核心变化是统一类型和类,这样做的好处是它允许您从内置类型继承。

阅读 descrintro 了解更多详细信息。

New-style classes inherit from object and must be written as such in Python 2.2 onwards (i.e. class Classname(object): instead of class Classname:). The core change is to unify types and classes, and the nice side-effect of this is that it allows you to inherit from built-in types.

Read descrintro for more details.

椒妓 2024-07-12 04:07:11

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

super(类型[,对象或类型])

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

在 Python 3.x 中,您可以简单地在类中使用 super() ,而不需要任何参数。

New style classes may use super(Foo, self) where Foo is a class and self is the instance.

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

Return a proxy object that delegates method calls to a parent or sibling class of type. This is useful for accessing inherited methods that have been overridden in a class. The search order is same as that used by getattr() except that the type itself is skipped.

And in Python 3.x you can simply use super() inside a class without any parameters.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文