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

Python中的旧样式类和新样式类之间有什么区别?,python,class,oop,types,new-style-class,Python,Class,Oop,Types,New Style Class,Python中的旧样式类和新样式类之间有什么区别?我应该在什么时候使用一个或另一个?来自: 直到Python2.1,旧式类是用户唯一可用的风格。 (旧式)类的概念与类型的概念无关: 如果x是一个旧式类的实例,那么x.\uuuuuu class\uuuuuu 指定x的类别,但类型(x)始终是 这反映了一个事实,即所有旧式实例都独立于 它们的类是用一个名为 例如 在Python2.2中引入了新样式的类,以统一类和类型的概念。 新样式的类只是用户定义的类型,不多也不少 如果x是一个新样式类的实例,那么

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

来自:

直到Python2.1,旧式类是用户唯一可用的风格。

(旧式)类的概念与类型的概念无关: 如果
x
是一个旧式类的实例,那么
x.\uuuuuu class\uuuuuu
指定
x
的类别,但
类型(x)
始终是

这反映了一个事实,即所有旧式实例都独立于 它们的类是用一个名为 例如

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

如果x是一个新样式类的实例,那么
type(x)
通常是 与
x.\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu类
相同(尽管这不保证–a 允许新样式的类实例重写返回的值 对于
x.\uuuuu类\uuuuuu

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

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

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

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

新式阶级的行为不同于老式阶级 类中的一些重要细节除了什么类型 返回

其中一些更改是新对象模型的基础,如 调用特殊方法的方式。其他则是无法解决的“修复” 为了兼容性考虑,如方法 多重继承情况下的解析顺序

Python 3只有新样式的类

无论您是否从
对象
创建子类,类都是新样式的 在Python3中


新样式类继承自
对象
,并且必须在Python2.2以后的版本中以同样的方式编写(即
类类名(对象):
而不是
类类名:
)。核心的变化是统一类型和类,其良好的副作用是它允许您从内置类型继承


阅读了解更多详细信息。

声明方面:


新样式类继承自对象或其他新样式类

class NewStyleClass(object):
    pass

class AnotherNewStyleClass(NewStyleClass):
    pass
旧式的课程不会

class OldStyleClass():
    pass
Python 3注意:


Python3不支持旧样式的类,因此上面提到的任何一种形式都会产生一个新样式的类。

旧样式的类在属性查找方面仍然稍微快一些。这通常并不重要,但在性能敏感的Python 2.x代码中可能很有用:

class NewStyleClass(object):
    pass

class AnotherNewStyleClass(NewStyleClass):
    pass
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 在[3]中:A类: …:def_uuuinit_uuu(self): …:self.a=‘你好’ ...: 在[4]中:B类(对象): …:def_uuuinit_uuu(self): …:self.a=‘你好’ ...: 在[6]中:aobj=A() [7]中:bobj=B() 在[8]:%timeit aobj.a中 10000000个循环,最佳3个:每个循环78.7纳秒 在[10]中:%timeit bobj.a 10000000个循环,最佳3个:每个循环86.9纳秒 Guido写了一篇关于Python中新样式和旧样式类的非常棒的文章

Python3只有一个新样式的类。即使您编写了一个“旧式类”,它也是隐式地从
对象派生的


新样式类有一些旧样式类所没有的高级特性,例如
super
,新的,一些神奇的方法,等等。

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

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

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


在Python3.x中,您只需在类中使用
super()
,而无需任何参数。

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

  • 旧式班级

    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>
    >>>
    
    
    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>
    >>>
    
    class Person():
    _名称\u缓存={}
    定义初始化(self,name):
    self.name=名称
    定义新名称(cls,名称):
    返回cls.\u names\u cache.setdefault(名称,对象.\uuuu新的\uuuuu(cls,名称))
    ahmed1=人(“Ahmed”)
    ahmed2=人(“Ahmed”)
    打印ahmed1是ahmed2
    打印ahmed1
    打印ahmed2
    >>>假的
    >>>
    
  • 新型课堂

    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>
    >>>
    
    
    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>
    >>>
    
    类人(对象):
    _名称\u缓存={}
    定义初始化(self,name):
    self.name=名称
    定义新名称(cls,名称):
    返回cls.\u names\u cache.setdefault(名称,对象.\uuuu新的\uuuuu(cls,名称))
    ahmed1=人(“Ahmed”)
    ahmed2=人(“Ahmed”)
    打印ahmed2是ahmed1
    打印ahmed1
    打印ahmed2
    >>>真的
    >>>
    

  • 新旧风格课程之间的重要行为变化

    • 增加
    • MRO变更(解释如下)
    • 增加
    • 除非派生自
      异常
      (以下示例),否则无法引发新样式类对象
    • 增加
    MRO(方法解决顺序)已更改 其他答案中也提到了这一点,但这里有一个关于经典MRO和C3 MRO(用于新样式类)之间差异的具体示例