译文:http://wiki.woodpecker.org.cn/moin/PyTypesAndObjects
原文:http://www.cafepy.com/article/python_attributes_and_methods/
解释新式的Python对象(new-style):
-
<type 'type'> and <type 'object'>是什么东西
- 用户定义的类及实例是如何相互关联的,和内置类型有啥关系how user defined classes and instances are related to each other and to built-in types
- metaclass是什么
新 式类型New-style包含在Python2.2及以上,包括3.x。这些版本之间会有细微差异,不过这里涉及到的概念都是无差别的。本书讲的内容通常 被称作Python类型系统或Python对象模型Python type system, or the object model.
- 本书是以下系列的一部分:
- Python Types and Objects [即你所看到的]
This revision: 1.24
-
Author: shalabh@cafepy.com
图索引
示例索引
需要提前了解的
应该注意的一些:
- 本书涵盖新式 new-style 对象 (在Python 2.2中引入). 本书例子适用于Python 2.5 及以上,包括 Python 3.x.
- 本书不是为完全初学者写的. 而是针对已经对Python有所了解 (稍稍了解即可) 并希望对它了解更多的人.
- 本 书为掌握新式(new-style)属性访问及descriptors, properties等机制提供了所需的底层的要点。如果只对属性方法感兴趣,请移步至 Python Attributes and Methods, 阅读之后也就理解了本书的 Summary.
python之旅快乐?Happy pythoneering!
1. 基本概念
深入Object
怎样准确的表达python中object的含义呢? 系统中每个对象是一条规则 - 是一个实体的体现. 可以通过如下特征来确定一个对象:
- 有标识名字 (i.e. 给定两个名字我们可以判断他们是否指向同一个对象).
- 有值 - 对象可能包含一堆属性 (i.e. 比如可以通过 objectname.attributename获得其他对象).
- 有类型 type - 每个对象有一个确定的类型. 例如对象2的类型是 int ,对象 "joe" 的类型是 string.
- 有一个或多个 bases. 并非所有对象都有bases,一些特别的对象会有. A base 类似于面向对象术语中的超类或基类。
- 如果你更在意具体的对象在内存中怎样存放,而不是更想知道一些抽象的概念,
- 这对你理解每个对象在内存中都有个具体的位置(可以用id函数来获得)很有帮助。(---注:这句瞎解得,没真正理解,附原文)
- If you are more of the 'I like to know how the bits are laid out' type as opposed to the 'I like the meta abstract ideas' type, it might be useful for you to know that each object also has a specific location in main memory that you can find by calling the id() function.
==== type 和 bases === (如果存在的话) 很重要,因为它们定义了对象和其他对象之间的特定关系. 请记住对象的types 和 bases只是另外一些对象.很快就会看到这一点.
你可能会想到对象有名字但名字不是对象的一部分. 对象名在对象之外的命名空间中存在(比如函数的本地变量) 或者作为另一个对象的属性.
即使对2这样一个简单对象所包含的东西也比我们眼睛看到的要多.
Example1.1. 查看integer对象
>>> two = 2 1 >>> type(two) <type 'int'> 2 >>> type(type(two)) <type 'type'> 3 >>> type(two).__bases__ (<type 'object'>,) 4 >>> dir(two) 5 ['__abs__', '__add__', '__and__', '__class__', '__cmp__', '__coerce__', '__delattr__', '__div__', '__divmod__', '__doc__', '__float__', '__floordiv__', '__format__', '__getattribute__', '__getnewargs__', '__hash__', '__hex__', '__index__', '__init__', '__int__', '__invert__', '__long__', '__lshift__', '__mod__', '__mul__', '__neg__', '__new__', '__nonzero__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'conjugate', 'denominator', 'imag', 'numerator', 'real']
- 1 在当前命名空间中我们把这个integer命名为two.
-
2 <type 'int'>. 这是另一个对象, 现在来解剖一下. 注意这个对象也被称为 int 而 <type 'int'> 只是它打印出来的样子.
-
3 <type 'int'> 的type是另外一个叫做 <type 'type'>的对象象.
-
4 <type 'int'> 的bases属性是一个tuple,这个tuple包含一个叫 <type 'object'>的对象. 我想你没考虑过检查 bases这个属性 ;).
- 5 列出这个原始integer对象的所有属性来 - 好多东西啊.
耐心点先来看我们的第一条规则
- 规则1
-
- 任何东西都是一个object
int 是 object. 这不是说例如2和77这样的数字是object (他们确实是), 而是说确实有另外一个对象叫做 int ,他处于内存中的实际的整数之外的内存中. 实际上所有的整数对象的class属性都指向 int,他们共同的心声是"知我者int也". 在一个object上调用type()方法返回的也正好是这个对象的class属性的值.
我们定义的所有classes都是对象, 当然这些classes的实例也是对象.甚至我们定义的方法和函数也是对象. 并且像我们看到的,这些对象都有些不同.
空白状态
现在我们来从头构建python的对象系统. 我们从一个空白状态开始。第一个框中的对象产生第二个框的对象,第二个框的对象产生第三个框的对象。
然后每个框中的对象有继承关系。即横向是实例化,纵向是继承
Figure 1.1. 空白状态
你可能在想为啥有两天灰色的竖线. 后面慢慢来揭晓. 竖线是来区别不同的区域的. 这个空白图中, 我们来逐渐加上各种对象,画上他们之间的关系,慢慢画满.
这个有助于帮助我们暂且搁置先入为主的各种有关面向对象的类和对象的观念,以对象的方式(我们这里的对象)来理解一切。
- At this point, it helps if any preconceived object oriented notions of classes and objects are set aside, and everything is perceived in terms of objects (our objects) and relationships.
对象之间的关系
我们使用两种关系就可以连接我们所引入的这许多不同的对象. 这两种关系是子类-父类关系 (也可叫做特别化或继承, 如"人是个动物", 等等.) 和类-实例关系 (也叫实例化, 比如"Joe是个人", 等等.)。
如果你对这些概念已经熟悉了,可以继续往下看了,否则的话你可能需要先去看看这一部分“面向对象”.
2.引入对象
第一批对象
我们来查看<type 'object'> 和 <type 'type'>这两个对象.
Example 2.1. Examining <type 'object'> and <type 'type'>
>>> object 1 <type 'object'> >>> type 2 <type 'type'> >>> type(object) 3 <type 'type'> >>> object.__class__ 4 <type 'type'> >>> object.__bases__ 5 () >>> type.__class__ 6 <type 'type'> >>> type.__bases__ 7 (<type 'object'>,)
-
1 2 这是python中两个最基本对象. 前面我们介绍过用type()来查看一个对象object的类型type(通常就是class属性的值). 其实,它本身是个对象,并且也是个查看其他对象类型的方式
-
3 4 5 查看 <type 'object'>: <type 'object'>的类型type是<type 'type'>. 我们也验证了它的class属性确实和调用type()是一样的.
-
6 7 查看 <type 'type'>: 有趣的是<type 'type'>的type是它自己! 它的bases属性包含了 <type 'object'>.
下面我们来画一下所看到的.
Figure 2.1. 鸡和蛋的关系
图中两个对象是python最基本对象. 也可以一次介绍一个,但这里有个鸡和蛋一样的矛盾 - 先介绍哪个好? 这两个对象是互相依赖的 - 每一个本身都不能单独存在,都要借助对方来描述自己.
还是继续我们的python实验吧:
Example 2.2. 关于 <type 'object'> 和 <type 'type'>的更多内容
>>> isinstance(object, object) 1 True >>> isinstance(type, object) 2 True
-
1 看看发生了什么? 这是 Dashed Arrow Up Rule 的一个应用. 由于<type 'type'> 是 <type 'object'>的子类, 则<type 'type'> 的实例也是<type 'object'>的实例.
- 2 将 Dashed Arrow Up Rule 和 Dashed Arrow Down Rule 一起使用, 直接把箭头反过来也是正确的. (译注:事实上type,objcet的两两组合都是互为instance的)
如果对上面的证明不太理解, 没关系 - 反正也没什么用.
再看一个新概念 - 类对象type objects. 我们介绍过的对象都是类对象. 所说的类对象是什么呢? 类对象有如下共同特点:
- 它们用来代表程序中抽象的数据类型. 例如, 用户定义的一个叫User的对象可能用来表示系统中所有的用户,另一个叫int的对象可能代表所有的整数.
- 它们可以被子类化. 你可以新建一个与已存在的类对象有点类似的新对象.已存在的类对象将成为这个新对象的基类.
-
它们可以被实例化. 意味着你可以新建一个已存在对象的实例. 这个新对象的class属性就是已存在对象.
-
任何类对象的类型是 <type 'type'>.
- 它们有时被称为types有时称为classes.
是 的. Types和classes在Python中确实是同一个东西 (免责声明: 对老式类和早于2.2版本的Python不适用. 那是 types和classes有些不同但那时很久前的事了,现在已这些不同点已经一致了。因此让过去的事就过去吧,不好吗?). 不要吃惊,使用type()函数和class属性得到的是一样的.
class 这个术语传统是指被class这个关键字创建的class. 内置类型 (比如int和string)通常不和classes联系起来, 这更多是约定俗成的,实际上types和classes是同一个东西.我觉得这点很重要,可以提出一个规则:
- Class is Type is Class
-
-
type和class这两个术语在所有Python >= 2.3的版本中是一样的.
-
类 对象Types 和 (嗯,,让我想个更好的词) 非类对象non-types (呵呵!) 都是对象 但只有types可以子类化. Non-types代表的是具体的值所以子类化并没有意义. 非类对象的两个例子是整数 2 以及字符串 "hello". 想想,2的子类是什么意思,没意思吧?
还对判断类对象和非类对象感觉混淆吗?有一个简单的规则:
- 类和非类对象判断规则Type Or Non-type Test Rule
-
-
如果一个对象是<type 'type'>的实例, 那它就是类对象. 否则是非类对象.
-
回头看,可以证明这个规则对我们所碰到的所有对象都是成立的, 包括 <type 'type'>,它是自己的实例.
总结一下:
-
<type 'object'> 是 <type 'type'>的一个实例.
-
<type 'object'> 不是任何类的子类.
-
<type 'type'> 是自己的实例.
-
<type 'type'> 是 <type 'object'>的子类.
- python 中只有两种对象: 为了清楚叫它们types 和 non-types. Non-types 也可以叫实例, 但实例这个术语也可以指向一个类对象, 因为一个type一定是另一个的type的实例. Types 也被叫做 classes, 并且我经常把他们叫做classes.
-
Note that we are drawing arrows on our slate for only the direct relationships, not the implied ones (i.e. only if one object is another's class, or in the other's bases). This make economic use of the slate and our mental capacity.
更多内置类型
Python中不止这两个对象,这两个基本对象有一堆的兄弟
Figure 2.2. 一些内置类型
上面展示了一些内置对象,下面解释一下.
Example 2.3. 查看一些内置类型
>>> list 1 <type 'list'> >>> list.__class__ 2 <type 'type'> >>> list.__bases__ 3 (<type 'object'>,) >>> tuple.__class__, tuple.__bases__ 4 (<type 'type'>, (<type 'object'>,)) >>> dict.__class__, dict.__bases__ 5 (<type 'type'>, (<type 'object'>,)) >>> >>> mylist = [1,2,3] 6 >>> mylist.__class__ 7 <type 'list'>
-
1 内置的<type 'list'> 对象.
-
2 <type 'list'>的类型是<type 'type'>.
-
3 它有一个基类 (即 superclass), <type 'object'>.
-
4 5 类似的还有 <type 'tuple'> 和 <type 'dict'>.
-
6 创建<type 'list'>的实例的方法.
-
7 一个list对象的type是 <type 'list>. 不要惊讶.
当创建一个tuple或dictionary对象时, 他们是各自对应类型的实例.
怎样创建一个mylist的实例呢? 不能. 因为 mylist对象不是一个type.
子类化产生新对象
内置对象是内置在python中的. 当我们启动python的时候就存在,通常程序结束的时候他们还存在.那我们怎样创建新对象呢?
新对象不会无中生有的出现. 它们必须通过现有的对象来创建.
Example 2.4. 通过子类化构建对象
# Python 2.x: class C(object): 1 pass # Python 3.x, 确定的object基类已经不需要指定了, 默认创建的都是class的基类: class C: 2 pass class D(object): pass class E(C, D): 3 pass class MyList(list): 4 pass
- 1 关键字class告诉python通过子类化已有类型来创建一个新类型.
- 2 不要在Python 2.x中这样写,这样得到的是一个旧式的类old-style class, 这里讲的这些在旧式类里都是不适用的.
- 3 可以有多个基类.
- 4 多数内置类型都可以被子类化(但不是全部).
从上面的例子可知, C.bases 包含 <type 'object'>, 而 MyList.bases 包含 <type 'list'>.
实例化产生新对象
子类化只是产生对象的一种方式,还有另外一种.
Example 2.5. 通过实例化构建对象
obj = object() 1 cobj = C() 2 mylist = [1,2,3] 3
- 1 2 调用操作符 (()) 通过实例化已有对象来创建新对象. 这里的已有对象必须是一个类对象type. 对于不同的类对象,这个调用操作符可能接受参数.
-
2 对某些内置类型python有特殊的语法来创建新对象. 方括号创建 <type 'list'>的实例; 整形数字直接量创建一个 <type 'int'>对象.
有了上面练习的这些, 我们的对象图就看起来更完美了.
Figure 2.3. 用户定义对象
注意,仅仅通过子类化 <type 'object'>, 类型C 自动成为 <type 'type'>的实例. 可以通过查看C.class来确认这一点. 下节再对此做解释.
其实都是实例化的
对于这一点你可能会冒出下面这些问题,也可能没有,不过我还是打算解答一下:
- Q: python是如何真正创建一个对象的?
-
A: python内部,当创建对象时, 肯定会使用一个type来创建这个type对象的一个实例. 具体的情况是调用这个类对象的new() 和 init() 方法(对这些内容的讨论已操作本书范围). 某种意义上,可以将类对象(type)看做是能够生产新对象的工厂. 这些生产出来的对象的类型(type)将是创建他们的类对象(type). 这就是为什么每个对象都有个类型type的原因.
- Q: 当实例化的时候我们指定了类型,但子类化的时候,python如果确定使用什么类型呢?
-
A: 这要看你子类化时指定的基类,将基类的类型type作为新对象(新类)的type,在 Example 2.4, “通过子类化构建对象”这个例子中 , <type 'type'> (指定的基类<type 'object'>的type) 被用做正在创建的C的类型.
想一下就会知道多数iqngk下, <type 'object'>的任何子类 (以及子类的子类,等等)都将被赋予<type 'type'>这个类型.
- 高级材料展望
-
- 一些更高级的讨论, 请仔细阅读, 或者跳到下一节.
- Advanced discussion ahead, tread with caution, or jump straight to the next section.
- Q: 我可以指定一个type来替代系统默认的机制吗?
-
A: 是的,一个可选方案就是用 metaclass 这个类的属性,如下示例:
Example 2.6. 使用class关键字定义类时指定一个type对象
class MyCWithSpecialType(object): __metaclass__ = SpecialType
-
这样Python在创建MyCWithSpecialType时,是实例化 SpecialType的, 而不是<type 'type'>.
-
Q: 太棒了,可以把任意type对象作为metaclass?
-
A: 不是的,指定的元类metaclass必须是所用的基类的type的子类No. It must be a subclass of the type of the base object. 比如上面的例子中:
-
MyCWithSpecialType 的基类是<type 'object'>.
-
<type 'object'>的 type是<type 'type'>.
-
所以如果用SpecialType做 metaclass的话, SpecialType必须是 <type 'type'>的子类才行.
-
使用像SpecialType这样的东西需要特别小心,这些已经超出本书的范围.
-
(译注,
似乎不是很确切,下面这个例子能运行。当然,我们不建议这么样,因为BClass的__metaclass__并不是AClass的元类的子类,
这就违反了__metaclass__的规则,你并不能确定BClass用的是自己定义的__metaclass__=type作元类,用查看BClass.__class__
,显示Atype。 class Atype(type): pass class AClass(object): __metaclass__ = Atype class BClass(AClass): __metaclass__ = type- 不过这个特性确实日常用的不多,不用深究了,作者也说超出本书范围,若有需求再 google吧。)
- 实测某些情况下,有个元类冲突错误the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases)
-
-
Q: 如果有多个基类,但没指定metaclass,会使用哪个type对象呢?
-
A: 好问题. 取决于python能否计算出用哪个。若所以基类有相同的type, 就是用这个. 若他们有不同的互不相干的type, python无法算出用哪个. 此时就需要指定一个metaclass, 并且这个metaclass 必须是每个基类的type的共同子类.
-
Q: 我什么时候应该用metaclass?
-
A: 永远别用 (只要你还问这个问题的话就别用
3. 总结一下
Python对象图
最后一章,我们最终得到一个有各种不同python对象的图
Figure 3.1. Python对象图
这一节我们也将解释图中灰色的竖线是干啥的. 根据人们对不同对象的叫法,灰色竖线将对象图分成三个区域 - 元类,类和实例.
- 观察这个图可以得出一些学究式的结论
-
虚线穿过了区域边界 (比如,从对象到元对象). 唯一的特例是<type 'type'> (也只能这样了, 否则就需要在它的左边再分一个另一个区域,另一个区域左边还得一个区域等等无穷尽。因为type的type就是自己啊).
-
实线不穿过边界. 又有一个例外, <type 'type'> -> <type 'object'> .
- 最右边的区域不能有实线. 它们是具体的对象,不能子类化.
- 虚线的箭头不能指向最右边区域. 具体的对象不能再实例化.
- 左边两个区域包含的是 types. 最右边区域包含的是non-types.
-
如果通过子类化<type 'type'>创建一个对象,它应该放在最左边的区域。并且它既是<type 'type'>的实例也是<type 'type'>的子类。
-
Also note that <type 'type'> is indeed a type of all types, and <type 'object'> a superclass of all types (except itself).
-
也要记住,<type 'type'>确实是所有类对象的type,而<type 'object'> 是所有类对象的超类(除了它自己)。
概要
总结一下谈到过的内容:
- python中有两种对象:
- - 可创建实例,可子类化.
- Non-type objects - 不能创建实例,不能子类化.
-
<type 'type'>;<type 'object'> 是python系统中的两个基本对象.
-
每个对象都有class,并且等于该对象的type.
-
每个type object有bases属性, 指向该对象的超类.只有<type 'object'>的bases是空的.
- 要通过子类化构建对象,我们使用class关键字,并指定新对象的基类bases (或者可选的 type) . 这样通常创建出的是type object.
- 要通过实例化构建对象, 需要使用在类对象上使用调用操作符即小括号 (())
-
某些non-type objects可以用特定的python语法创建.比如[1, 2, 3] 创建一个 <type 'list'>的实例.
- python在内部总是使用一个type object来创建一个新对象。创建出来的新对象是所用的type object的实例。通过class关键字创建的type object的类型的确定要看所指定的bases以及bases们的类型。
- issubclass(A,B) (测试超类-子类关系) ,以下情况返回True:
-
B在A.bases中,
-
对于A.bases中的每一个Z,如果 issubclass(Z,B)为True.(即若A的每个直接基类都是B的子类的话,就可以推导出 A也是B的子类)
-
- isinstance(A,B) (测试类型-实例关系) ,以下情况返回True:
-
BBA.class,
-
issubclass(A.class,B) 为True.(即若A的类型是B的子类的话,A也就是B的实例)
-
- 这样看来,我的Squasher确实也是蟒蛇. (没提过,不过现在你就知道了.)
好多内置类型还有个名字
Example 3.1. 更多内置 types
>>> import types 1 >>> types.ListType is list 2 True >>> def f(): 3 ... pass ... >>> f.__class__ is types.FunctionType 4 True >>> >>> class MyList(list): 5 ... pass ... >>> class MyFunction(types.FunctionType): 6 ... pass ... Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: type 'function' is not an acceptable base type >>> dir(types) 7 ['BooleanType', 'DictProxyType', 'DictType', ..]
- 1 types 模块中包含很多内置类型.
- 2 一些我们熟知的类型还有另外一个名字.
- 3 def 创建一个function对象.
-
4 function对象的类型是 types.FunctionType
- 5 有的内置类型可以被子类化.
- 6 但另一些不行.
- 7 还有更多我们没了解过的类型.
这些有什么意义
我们可以用我们选择的对象间的关系来创建新对象,但这对我们有什么用?
- 对象间的关系决定了对象属性的访问是怎么起作用的,例如,当使用objectname.attributename,我们得到哪个对象?这完全取决于该对象objectname,它的类型以及它的基类(如果有的话)。
python中的属性访问机制在本系列的第二本书中讲解:Python Attributes and Methods.
经典类型Classic Classes
这是一份关于python中的classic classes 的备忘录. 用一个空的class关键字可以创建老式(早于python2.2)的类.
>>> class ClassicClass: 1 ... pass ... >>> type(ClassicClass) 2 <type 'classobj'> >>> import types >>> types.ClassType is type(ClassicClass) 3 True >>> types.ClassType.__class__ 4 <type 'type'> >>> types.ClassType.__bases__ 5 (<type 'object'>,)
- 1 不指定基类的class关键字会创建老式的类,注意要创建新式的类必须指定对象作为基类(然而python3.0中不再需要指定基类,因为3.0中默认的 就是新式类)。 指定的基类中若只有老式类,那么创建出的也是老式类。若基类中老式的和新式的类都有的话创建出的就是新式的类。
- 2 这个类型本书中还没有看到过.
-
3 老式类的类型是一个叫types.ClassType 的对象.
- 4 5 看起来它也像是另外一种类对象.
types.ClassType这个对象某种程度上可替代<type 'type'>. 该对象的实例(即老式类) 该对象的实例 (老式类) 也是类对象types. 新老式对象之间的属性访问规则是不同的。 types.ClassType 这个对象的存在时为了向后兼容,在将来版本的python中可能就没有了. 本书的其他部分所讲的内容不应被套用到老式类上去。去。
请在这里评论: discussion page. 感谢反馈!
到处结束了,朋友们!
4. 可能在其他地方学过的
面向对象
可以略过的章节?Can Skim Section
- (注:这一节英文可能看着更舒服,翻译起来很费劲,感觉有些术语翻译了就变味了,尽量看原文吧)
用古怪的一节来讲解 类型-实例 和 超类-子类关系
我们引入很多不同的对象,他们之间只用两种关系就可以概括 ( 4.1. 关系)
- “是一类” (图中实线): 即面向对象中的特殊化, 当其中一个(即子类)是另一个(超类)的特殊情况时两对象间存在这种关系.蛇“是一种”爬虫. 它具有爬虫的所有特征并且也有自己作为蛇的一些独特的特征.
术语: *的子类, *的超类 and 超类-子类.
- “是一个实例子”(图中虚线): 也叫实例化, 当其中一个 (即实例)是另一个(即类型)的具体例子时两对象间存在这种关系. 我有一个宠物蛇叫Squasher. Squasher 是蛇的一个实例.
术语: *的实例, *的类型, 类型-实例 或 类-实例.
注意在简单英语中术语,以上两种关系都可以叫'是一个' . , 蛇是一个爬虫. 不过我们用特定的术语来避免混淆.
Figure 4.1. 关系
- 我们用实线表示第一种关系是因为对象之间很接近而不是一个和另一个有关系。例如,如果让列出和“蛇”最类似的词,人们很可能会说“爬虫”。但如果让列出和 'Squasher'最类似的词,人们不大可能说“蛇”
- We use the solid line for the first relationship because these objects are closer to each other than ones related by the second. To illustrate - if one is asked to list words similar to 'snake', one is likely to come up with 'reptile'. However, when asked to list words similar to 'Squasher', one is unlikely to say 'snake'.
- 基于这点,可以注意到下面的关系的属性
- It is useful at this point to note the following (independent) properties of relationships: 虚线向上规则Dashed Arrow Up Rule
- 如果X是A的实例,A是B的子类,则X也是B的实例.
- 如果B是M的实例,A是B的子类,则A也是M的实例.
换句话说, 虚线箭头一端可以向上移到实线箭头,虚线箭尾可以向下移 ( 如Figure 4.2. ""关系的传递" 中的2a和2b各自表示的).这些性质可以直接从父类-子类的关系定义得到
Figure 4.2. 关系的传递
应用 虚线向上规则, 可以从下面第一条描述得到第二条:
- Squasher 是蛇的实例 (Squasher的类型是蛇).
- Squasher 是爬虫的实例 (Squasher的类型是爬虫).
之前我们说过每个对象有一个确切的类型.为啥 Squasher有两个? 注意虽然每个说法都是正确的, 其中一个更确切 (确切的说可以归纳另一个).也可以说:
-
Squasher.class 是 snake. (Python中, 对象的class指向对象的type).
- isinstance(Squasher, snake) 和isinstance(Squasher, reptile) 都正确.
父类-子类关系也有个类似的规则.
- 合并实线规则
-
- 若A是B的子类, B是C的子类, 则A也是C的子类
蛇是一种爬虫, 爬虫是一种动物. 所有蛇也是一种动物. 或者用Python代码表示:
-
snake.bases 是 (reptile,). (对象的bases 属性是一个包含对象超类的元组).
- issubclass(snake, reptile) 和 issubclass(snake, animal) 都正确.
注意对象可能有不止一个基类.
相关资料
-
[descrintro] Unifying types and classes in Python 2.2 Guido van Rossum.
-
[pep-253] Subclassing Built-in Types Guido van Rossum.
版权信息
This book was written in DocBook XML. The HTML version was produced using DocBook XSL stylesheets and xsltproc. The PDF version was produced using htmldoc. The diagrams were drawn using OmniGraffe [1]. The process was automated using Paver [2].