13.12 类、实例和其他对象的内建函数

13.12.1 issubclass()

issubclass()布尔函数判断一个类是另一个类的子类或子孙类。它有如下语法:

13.12 类、实例和其他对象的内建函数 - 图1

issubclass()返回True的情况:给出的子类sub确实是父类sup的一个子类(反之,则为False)。这个函数也允许“不严格”的子类,意味着,一个类可视为其自身的子类,所以,这个函数如果当sub就是sup,或者从sup派生而来,则返回True(一个“严格的”子类是严格意义上的从一个类派生而来的子类)。

从Python 2.3开始,issubclass()的第二个参数可以是可能的父类组成的元组(tuple),这时,只要第一个参数是给定元组中任何一个候选类的子类时,就会返回True。

13.12.2 isinstance()

isinstance()布尔函数在判定一个对象是否是另一个给定类的实例时,非常有用。它有如下语法:

13.12 类、实例和其他对象的内建函数 - 图2

isinstance()在obj1是类obj2的一个实例,或者是obj2的子类的一个实例时,返回True(反之,则为False),看下面的例子:

13.12 类、实例和其他对象的内建函数 - 图3

注意:第二个参数应当是类;不然,你会得到一个TypeError。但如果第二个参数是一个类型对象,则不会出现异常。这是允许的,因为你也可以使用isinstance()来检查一个对象obj1是否是obj2的类型,比如:

13.12 类、实例和其他对象的内建函数 - 图4

如果你对Java有一定的了解,那么你可能知道Java中有个等价函数叫instanceof(),但由于性能上的原因,instanceof()并不推荐使用。调用Python的isinstance()不会有性能上的问题,主要是因为它只用来快速搜索类族集成结构,以确定调用者是哪个类的实例,还有更重要的是,它是用C写的!

同issubclass()一样,isinstance()也可以使用一个元组作为第二个参数。这个特性是从Python 2.2版本中引进的。如果第一个参数是第二个参数中给定元组的任何一个候选类型或类的实例时,就会返回True。你还可以在第13.16.1节中了解到更多有isinstance()的内容。

13.12.3 hasattr()、getattr()、setattr()、delattr()

attr()系列函数可以在各种对象下工作,不限于类(class)和实例(instances)。然而,因为在类和实例中使用极其频繁,就在这里列出来了。需要说明的是,当使用这些函数时,你传入你正在处理的对象作为第一个参数,但属性名,也就是这些函数的第二个参数,是这些属性的字符串名字。换句话说,在操作obj.attr时,就相当于调用attr(obj,‘attr’…)系列函数——下面的例子讲得很清楚。

hasattr()函数是布朗型的,它的目的就是为了决定一个对象是否有一个特定的属性,一般用于访问某属性前先作一下检查。getattr()和setattr()函数相应地取得和赋值给对象的属性,getattr()会在你试图读取一个不存在的属性时,引发AttributeError异常,除非给出那个可选的默认参数。setattr()将要么加入一个新的属性,要么取代一个已存在的属性。而delattr()函数会从一个对象中删除属性。

下面一些例子使用到了*attr()系列内建函数:

13.12 类、实例和其他对象的内建函数 - 图5

13.12 类、实例和其他对象的内建函数 - 图6

13.12.4 dir()

前面用到dir()是在练习2-12、练习2-13和练习4-7。在这些练习中,我们用dir()列出一个模块所有属性的信息。现在你应该知道dir()还可以用在对象上。

在Python 2.2中,dir()得到了重要的更新。因为这些改变,那些membersmethods数据属性已经被宣告即将不支持。dir()提供的信息比以前更加详尽。根据文档,“除了实例变量名和常用方法外,它还显示那些通过特殊标记来调用的方法,像iadd(+=),len(len()),ne(!=)”。在Python文档中有详细说明。

  • dir()作用在实例上(经典类或新式类)时,显示实例变量,还有在实例所在的类及所有它的基类中定义的方法和类属性。

  • dir()作用在类上(经典类或新式类)时,则显示类以及它的所有基类的dict中的内容。但它不会显示定义在元类(metaclass)中的类属性。

  • dir()作用在模块上时,则显示模块的dict的内容。(这没改动)。

  • dir()不带参数时,则显示调用者的局部变量。(也没改动)。关于更多细节:对于那些覆盖了dictclass\属性的对象,就使用它们;出于向后兼容的考虑,如果已定义了_membersmethods,则使用它们。

13.12.5 super()

super()函数在Python2.2版本新式类中引入。这个函数的目的就是帮助程序员找出相应的父类,然后方便调用相关的属性。一般情况下,程序员可能仅仅采用非绑定方式调用祖先类方法。使用super()可以简化搜索一个合适祖先的任务,并且在调用它时,替你传入实例或类型对象。

在第13.11.4节中,我们描述了方法解释顺序(MRO),用于在祖先类中查找属性。对于每个定义的类,都有一个名为mro的属性,它是一个元组,按照他们被搜索时的顺序,列出了备搜索的类。语法如下:

13.12 类、实例和其他对象的内建函数 - 图7

给出type,super()“返回此type的父类”。如果你希望父类被绑定,你可以传入obj参数(obj必须是type类型的)。否则父类不会被绑定。obj参数也可以是一个类型,但它应当是type的一个子类。通常,当给出obj时:

  • 如果obj是一个实例,isinstance (obj,type)就必须返回True

  • 如果obj是一个类或类型,issubclass (obj,type)就必须返回True

事实上,super()是一个工厂函数,它创造了一个super object,为一个给定的类使用mro去查找相应的父类。很明显,它从当前所找到的类开始搜索MRO。更多详情,请再看一下贵铎·范·罗萨姆有关统一类型和类的文章,他甚至给出了一个super()的纯Python实现,这样,你可以加深其印象,知道它是如何工作的!

最后想到…super()的主要用途,是来查找父类的属性,比如super (MyClass,self).init()。如果你没有执行这样的查找,你可能不需要使用super()。

有很多如何使用super()的例子分散在本章中。记得阅读一下第13.11.2节中有关super()的重要提示,尤其是核心笔记。

13.12.6 vars()

vars()内建函数与dir()相似,只是给定的对象参数都必须有一个dict属性。vars()返回一个字典,它包含了对象存储于其dict中的属性(键)和值。如果提供的对象没有这样一个属性,则会引发一个TypeError异常。如果没有提供对象作为vars()的一个参数,它将显示一个包含本地名字空间的属性(键)及其值的字典,也就是,locals()。我们来看一下例子,使用类实例调用vars():

13.12 类、实例和其他对象的内建函数 - 图8

表13.3概括了类和类实例的内建函数。

13.12 类、实例和其他对象的内建函数 - 图9

13.12 类、实例和其他对象的内建函数 - 图10