返回介绍

新式类变化

发布于 2024-01-29 22:24:15 字数 3505 浏览 0 评论 0 收藏 0

新式类在几个方面不同于经典类,其中的一些很细微,但可能会影响到已有的Python 2.X代码和编码方式。下面是它们不同的主要方面:

类和类型合并

类现在就是类型,并且类型现在就是类。实际上,这二者基本上是同义词。type(I)内置函数返回一个实例所创建自的类,而不是一个通用的实例类型,并且,通常是和I.__class__相同的。此外,类是type类的实例,type可能子类化为定制类创建,并且所有的类(以及由此所有的类型)继承自object。

继承搜索顺序

多继承的钻石模式有一种略微不同的搜索顺序,总体而言,它们可能先横向搜索再纵向搜索,并且先宽度优先搜索,再深度优先搜索。

针对内置函数的属性获取

__getattr__和__getattribute__方法不再针对内置运算的隐式属性获取而运行。这意味着,它们不再针对__X__运算符重载方法名而调用,这样的名称搜索从类开始,而不是从实例开始。

新的高级工具

新式类有一组新的类工具,包括slot、特性、描述符和__getattribute__方法。这些工具中的大多数都有非常特定的工具构建目的。

我们在第27章的边栏部分简单地介绍了这些变化中的3个,并且,我们将在第37章的属性管理介绍中以及第38章的私有性装饰器介绍中更深入地回顾它们。由于上面列出的第1个变化和第2个变化可能影响到已有的Python 2.X代码,让我们在介绍新式类之前,更详细地看看这些工具。

类型模式变化

在新式类中,类型和类的区别已经完全消失了。类自身就是类型:type对象产生类作为自己的实例,并且类产生它们的类型的实例。实际上,像列表和字符串这样的内置类型和编写为类的用户定义类型之间没有真正的区别。这就是为什么我们可以子类化内置类型,就像本章前面所介绍的那样,由于子类化一个列表这样的内置类型,会把一个类变为新式的,因此,它变成了一个用户定义的类型。

除了允许子类化内置类型,还有一点变得非常明显的情况,就是当我们进行显式类型测试的时候。使用Python 2.6的经典类,一个类实例的类型是一个通用的“实例”,但是,内置对象的类型要更加特定:

但是,对于Python 2.6中的新式类,一个类实例的类型是它所创建自的类,因为类直接是用户定义的类型——实例的类型是它的类,并且,用户定义的类的类型与一个内置对象类型的类型相同。类现在有一个_class__属性,因为它们也是type的实例:

对于Python 3.0中的所有类都是如此,因为所有的类自动都是新式的,即便它们没有显式的超类。实际上,内置类型和用户定义类型之间的区分,在Python 3.0中消失了:

正如你所看到的,在Python 3.0中,类就是类型,但是,类型也是类。从技术上讲,每个类都由一个元类生成——元类是这样的一个类,它要么是type自身,要么是它定制来扩展或管理生成的类的一个子类。除了影响到进行类型测试的代码,这对于工具开发者来说,是一个重要的钩子。我们将在本章后面讨论元类,并且将在第39章再次详细介绍它。

类型测试的隐含意义

除了提供内置类型定制和元类钩子,新的类模式中类和类型的融合,可能会影响到进行类型测试的代码。例如,在Python 3.0中,类实例的类型直接而有意义地比较,并且以与内置类型对象同样的方式进行。下面的代码源自于这样的一个事实:类现在是类型,并且一个实例的类型是该实例的类。

对于Python 2.6或更早版本中的经典类,比较实例类型几乎是无用的,因为所有的实例都具有相同的“实例”类型。要真正地比较类型,必须要比较实例__class__属性(如果你关注可移植性,这在Python 3.0中也有效,但在那里不是必需的):

并且,正如你所期待的,在这方面,Python 2.6中的新式类与Python 3.0中的所有类同样地工作——比较实例类型会自动地比较实例的类:

当然,正如我们在本书中多次指出的,类型检查通常在Python程序中是错误的事情(我们编写对象接口,而不是编写对象类型),并且更加通用的isinstance内置函数很可能是你在极少数情况下(即必须查询实例类的类型的情况下)想要使用的。然而,知道Python的类型模型的知识,通常对于了解类模型有帮助。

所有对象派生自object

新式类模式中的另一个类型变化是,由于所有的类隐式地或显式地派生自(继承自)类object,并且,由于所有的类型现在都是类,所以每个对象都派生自object内置类,不管是直接地或通过一个超类。考虑Python 3.0中的如下交互模式(在Python 2.6中编写一个显式的object超类,会有等价的效果):

和前面一样,一个类实例的类型就是它所产生自的类,并且,一个类的类型就是type类,因为类和类型都融合了。确实是这样,但是,实例和类都派生自内置的object类,因此,每个类都有一个显式或隐式的超类:

对于列表和字符串这样的内置类型来说,也是如此,因为在新模式中,类型是类——内置类型现在也是类,并且它们的实例也派生自object:

实际上,类型自身派生自object,并且object派生自type,即便二者是不同的对象——一个循环的关系覆盖了对象模型,并由此导致了这样一个事实:类型是生成类的类。

实际上,这种模式导致了比前面的经典类的类型/类区分的几个特殊情况,并且,它允许我们编写假设并使用一个object超类的代码。我们将在本书稍后看到示例,现在,让我们继续介绍其他的新式类变化。

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

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

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文