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

2024-11-22 08:47:00
admin
原创
152
摘要:问题描述:Python 中的旧式类和新式类有什么区别?我什么时候应该使用其中一种?解决方案 1:来自新式和古典类:直到 Python 2.1,旧式类是用户唯一可用的风格。(旧式) 类的概念与类型的概念无关:如果x是旧式类的实例,则x.__class__ 指定 的类x,但type(x)始终为`<type ...

问题描述:

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


解决方案 1:

来自新式和古典类

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

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

这反映了这样一个事实:所有旧式实例(与其类无关)都是用一个称为实例的内置类型实现的。

Python 2.2 引入了新式类,以统一类和类型的概念。新式类只是一种用户定义的类型,仅此而已。

如果 x 是新式类的实例,则type(x)通常与相同x.__class__(尽管不能保证——新式类实例可以覆盖的返回值x.__class__)。

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

它还具有许多直接的好处,例如能够对大多数内置类型进行子类化,或者引入“描述符”,从而实现计算属性。

由于兼容性原因,类默认仍是旧式的

通过指定另一个新式类(即类型)作为父类来创建新式类,如果不需要其他父类,则指定“顶级类型”对象。

除了返回类型之外,新式类的行为在许多重要细节上也不同于旧式类。

其中一些变化是新对象模型的基础,例如调用特殊方法的方式。其他一些变化是以前因兼容性问题而无法实现的“修复”,例如多重继承情况下的方法解析顺序。

Python 3 只有新式类

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

解决方案 2:

声明方面:

新式类继承自object,或者继承自另一个新式类。

class NewStyleClass(object):
    pass

class AnotherNewStyleClass(NewStyleClass):
    pass

旧式课程则不然。

class OldStyleClass():
    pass

Python 3 注意事项:

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

解决方案 3:

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

  • 超级添加

  • 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

解决方案 4:

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

在[3]中:A类:
   ...: def __init__(self):
   ...: self.a = '你好'
   ...:

在[4]中:B类(对象):
   ...: def __init__(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 纳秒

解决方案 5:

Guido 撰写了《新式类的内幕故事》,这是一篇关于 Python 中新式类和旧式类的非常棒的文章。

Python 3 只有新式类。即使你写了一个“旧式类”,它也隐式地从中派生出来object

新式类具有一些旧式类所缺乏的高级特性,比如super,新的C3 mro,一些魔法方法等。

解决方案 6:

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

  1. 新式课程

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>
>>>

解决方案 7:

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

阅读描述以了解更多详细信息。

解决方案 8:

新风格的类可能会使用super(Foo, self)其中Foo是一个类并且self是实例。

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

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

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

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用