[译]Python中的Types和Objects

1. 关于本篇文章

解释了Python中的新风格objects:

  • <type ‘type’>和<type ‘object’>是什么。
  • 用户自定义的类和实例之间、用户自定义的类和实例与内建类型之间是如何关联的。
  • 元类(metaclasses)是什么。

新风格是指Python 2.2到Python 3.x之间。在这些版本间有一些特性发生了改变,但本文中提到的这些概念都是通用的。本文中描述的内容有时被称为Python type system或者object model。
译者注:object is a base for all new style classes
 

2. 基本概念

2.1 Python中的object

那么Python object究竟是什么东西?Object是Python中的公理 – 它代表实体。但我们仍然可以通过下面几条来定义Python中的object:

  • 有标识(例如,给定两个名字我们可以确定它们是否指向同一个object)
  • 有值(value)
  • 有类型(type)
  • 一个或多个bases.在面向对象中,你可以把这里的bases理解为基类或者超类。

如果你是那种追根究底的人,想知道object的内部机制,那么在这里我在讲一个知识点:每一个object都位于内存之中,通过id()这一函数可以获取object的地址值。
Type和bases(如果存在的话)的概念之所以重要,是因为它们定义了object和其他objects之间的relationship。记住,objects的types和bases也是objects。后面我还会提到这一点。
你可能会认为object有名字,但实际上名字并不是object的一部分。名字存在于object之外,名字存在于命名空间或者作为另一个object的属性。
即便像数字‘2’这样一个简单的例子,其背后的机制远不像表面上看起来的这么简单。

Example 1.1. Examining an integer object

>>> 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 Here we give an integer the name two in the current namespace.
2 The type of this object is <type 'int'>. This <type 'int'> is another object, which we will now explore. Note that this object is also called just int and <type 'int'> is the printable representation.
3 Hmm.. the type of <type 'int'> is an object called <type 'type'>.
4 Also, the __bases__ attribute of <type 'int'> is a tuple containing an object called <type 'object'>. Bet you didn’t think of checking the __bases__ attribute ;).
5 Let’s list all the attributes present on this original integer object – wow that’s a lot.

也许你会问了:上面这个例子究竟说明了什么?大家不要着急,我先来说说下面这条规则:

Rule 1

Everything is an object

内建的int类型是一个object。但这并不代表仅仅是像2或者77这样的数字是objects,实际上还有另一个叫做int的object,它被保存在那些数字的值旁边(译者注:实际上,像int这种type object,多次运行id(int),其返回值是不会改变的)。所有的整型objects都有 __class__这一属性,而__class__值就是指向int的,用来表明“那家伙(int)懂我”。type()函数便是返回一个object的 __class__属性值。

我们定义的任何类都是objects。当然,这些类的实例也都是objects。甚至函数和方法也是objects。当然,各个objects并非是完全相同的。

2.2 A Clean Slate

现在我们从零开始构造Python的object system。先从一个空表格开始。
A Clean Slate
你也许会好奇为什么我要画这样一个图,这只是一个空图,后面我会逐步在上面加上不同的objects,并画出它们间的关系。(译者注:这里的三列从左到右分别代表metaclass,class,instance。metaclass可以理解成class的模板,一个class根据metaclass作为模板而生成出来。)
此时,让我们把之前我们了解的OOP知识先放一边,先从objects(我们定义的objects)和relationships开启此次学习之旅。

2.3 对象间的关系

我们使用两种relationships来连接不同的objects。一种是子类-父类(如:人是一种动物),一种是类型-实例(如Joe是一个人)。如果你对此概念不熟悉,可以先看看这里 the section called “Object-Oriented Relationships”

3. 引入对象

3.1 The First Objects

先来解释两个object: <type 'object'> and <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 The names of the two primitive objects within Python. Earlier type() was introduced as a way to find the type of an object (specifically, the __class__ attribute). In reality, it is both – an object itself, and a way to get the type of another object.
3 4 5 Exploring <type 'object'>: the type of <type 'object'> is <type 'type'>. We also use the __class__ attribute and verify it is the same as calling type().
6 7 Exploring <type 'type'>: interestingly, the type of <type 'type'> is itself! The __bases__ attribute points to <type 'object'>.

Figure 2.1. Chicken and Egg

Chicken and Egg

这两个objects是Python中的基础object。如果我将它们两个分开介绍的话,就会出现’先有鸡还是先有蛋’的问题 – 究竟该从哪个开始介绍?实际上这两个objects是互相依赖的 – 它们的定义中互相包含。
那么现在继续我们的试验:

Example 2.2. There’s more to <type 'object'> and <type 'type'>

>>> isinstance(object, object) 1   译者注:这里应该是 isinstance(object, type),运行结果为True
True
>>> isinstance(type, object) 2
True
1 Whoa! What happened here? This is just Dashed Arrow Up Rule in action. Since <type 'type'> is a subclass of <type 'object'>, instances of <type 'type'> are instances of <type 'object'> as well.
2 Applying both Dashed Arrow Up Rule and Dashed Arrow Down Rule, we can effectively reverse the direction of the dashed arrow. Yes, it is still consistent.

 
 
The solid arrow is the issubclass relationship. The dashed arrow is the isinstance relationship. The dashed arrow could be double ended, but that is not necessary because it automatically follows from the other relationships (Example 2.2).
While subclassing an instance makes no sense in C++, in Python all classes are techincally instances and so subclassing makes sense.
If coming from C++, you basically have to forget the C++ concept of classes and assume all Python classes, meta-classes and objects are like C++ instances. All these ‘instances’ are located in memory and hold references to each other. There are two kinds of references (or edges in this graph of objects) – isinstance and issubclass. How the objects are connected determine how they behave.
Anyway, parts of this book seem too pedantic now and can probably be reduced or simplified.
总是,作者就是为了说明:

Class is Type is Class

type和class这两个术语在所有Python >= 2.3的版本中是一样的。
(译者注:然后作者又来唠叨了,其实这不是废话么?用过C++或者Java的都知道吧,不就是程序中要么是class要么是instance么。只是在Python中,class也是object而已。)

还对判断类对象和非类对象感觉混淆吗?有一个简单的规则:

Type Or Non-type Test Rule

如果一个对象是<type ‘type’>的实例, 那它就是类对象. 否则是非类对象。

回头看,可以证明这个规则对我们所碰到的所有对象都是成立的, 包括 <type ‘type’>,它是自己的实例.

总结一下:

  1. <type ‘object’> 是 <type ‘type’>的一个实例.

  2. <type ‘object’> 不是任何类的子类.

  3. <type ‘type’> 是自己的实例.

  4. <type ‘type’> 是 <type ‘object’>的子类.

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

3.2 更多内置类型

Python中不止这两个对象,这两个基本对象有一堆的兄弟。

Figure 2.2. Some Built-in Types

Some Built-in Types
实线箭头代表继承关系- issubclass,而虚线箭头代表isinstance关系(注意这与UML中的虚线箭头不一样,UML中虚线箭头代表实现接口的意思)

上图就是说明:list tuple dict这些类型都是从object继承过来的,然后这些类型是<type ‘type’>的实例。
下面是一些built-in类型的例子。
Example 2.3. Examining some built-in types

>>> 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 The built-in <type 'list'> object.
2 Its type is <type 'type'>.
3 It has one base (a.k.a. superclass), <type 'object'>.
4 5 Ditto for <type 'tuple'> and <type 'dict'>.
6 This is how you create an instance of <type 'list'>.
7 The type of a list is <type 'list>. No surprises here.

当我们创建一个tuple或者dictionary,它们便是各自类型的实例。
那么我们怎么创建一个称之为mylist的实例呢?现在还不能,因为我们还有创建mylist这一类型。

3.3 New Objects by Subclassing

内建的objects通常从Python程序开始便存在,在程序结束时消失。那么我们如何创建新的objects?
新的objects不会从石头缝里自己冒出来。我们通过已存在的objects来创建新的objects。
Example 2.4. Creating new objects by subclassing
# In Python 2.x:
class C(object): 1
    pass
# In Python 3.x, the explicit base class is not required, classes are
# automatically subclasses of object:
class C: 2
    pass
class D(object):
    pass
class E(C, D): 3
    pass
class MyList(list): 4
    pass
1 The class statement tells Python to create a new type by subclassing an existing type.
2 Don’t do this in Python 2.x or you will end up with an object that is an old-style class, everything you read here will be useless and all will be lost.
3 Multiple bases are fine too.
4 Most built-in types can be subclassed (but not all).

After the above example, C.__bases__ contains <type 'object'>, and MyList.__bases__ contains <type 'list'>.
在上例中,C.__bases__包含<type ‘object’>,MyList.__bases__ 包含 <type 'list'>。

3.4 New Objects by Instantiating

除了继承外,还有别的方式创建新的object。(译者注:继承就是生成新的type-object,而这里所说的别的方式是指通过类生成新的实例)
Example 2.5. Creating new objects by instantiating

obj = object() 1
cobj = C() 2
mylist = [1,2,3] 3
1 2 The call operator (()) creates a new object by instantiating an existing object. The existing object must be a type. Depending on the type, the call operator might accept arguments.
2 Python syntax creates new objects for some built-in types. The square brackets create an instance of <type 'list'>; a numeric literal creates an instance of <type 'int'>.

After the above exercise, our slate looks quite full.
通过上面的这些例子,我们的示意图基本上画好了。
Figure 2.3. User Built Objects

User Built Objects

我们注意C通过继承自<type ‘object’>的object,其type会是<type ‘type’>的实例,并且是自动成为<type ‘type’>的实例。在下一节我会解释为什么。

3.5 It’s All Instantiation, Really

也许此时你头脑中会有一些疑问,来一个Q&A吧:

Q: How does Python really create a new object?
A: Internally, when Python creates a new object, it always uses a type and creates an instance of that object. Specifically it uses the __new__() and __init__() methods of the type (discussion of those is outside the scope of this book). In a sense, the type serves as a factory that can churn out new objects. The type of these manufactured objects will be the type object used to create them. This is why every object has a type.
Q: When using instantiation, I specify the type, but how does Python know which type to use when I use subclassing?
A: It looks at the base class that you specified, and uses its type as the type for the new object. In the exampleExample 2.4, “Creating new objects by subclassing” , <type 'type'> (the type of <type 'object'>, the specified base) is used as the type object for creating C.A little thought reveals that under most circumstances, any subclasses of <type 'object'> (and their subclasses, and so on) will have <type 'type'> as their type.

Advanced Material Ahead

下面是一些高级内容,你可以直接跳到下一章。

Q: Can I instead specify a type object to use?
A: Yes. One option is by using the __metaclass__ class attribute as in the following example:

Example 2.6. Specifying a type object while using class statement

class MyCWithSpecialType(object):
    __metaclass__ = SpecialType


Now Python will create MyCWithSpecialType by instantiating SpecialType, and not <type 'type'>.

Q: Wow! Can I use any type object as the __metaclass__?
A: No. It must be a subclass of the type of the base object. In the above example:

  • Base of MyCWithSpecialType is <type 'object'>.
  • Type of <type 'object'> is <type 'type'>.
  • Therefore SpecialType must be a subclass of <type 'type'>.

Implementation of something like SpecialType requires special care and is out of scope for this book.

Q: What if I have multiple bases, and don’t specify a __metaclass__ – which type object will be used?
A: Good Question. Depends if Python can figure out which one to use. If all the bases have the same type, for example, then that will be used. If they have different types that are not related, then Python cannot figure out which type object to use. In this case specifying a __metaclass__ is required, and this __metaclass__ must be a subclass of the type of each base.
Q: When should I use a __metaclass__?
A: Never (as long as you’re asking this question anyway 🙂

4. 总结

4.1 The Python Objects Map

最后我们得到了一个完整的示例图。
Figure 3.1. The Python Objects Map

The Python Objects Map

这里我标出了图片中划分的三个区域分别对应的是什么,他们分别是metaclasses,classes,instances。
我们发现, <type 'type'>是所有类型的type,<type 'object'>是所有类型的基类。

4.2 Summary

总结上述内容:

  • Python中有两种object:
    1. Type objects – 可以被继承,可以用来创建实例。
    2. Non-type objects – 不可以被继承,不可以用来创建实例。
  • <type 'type'> 和 <type 'object'> 是两个最基础的object。
  • objectname.__class__ 存在于每个object中,且指向此object的type。
  • objectname.__bases__ 存在于每个type object中,且指向自己的父类。只有<type ‘object’>的__bases__为空。
  • To create a new object using subclassing, we use the class statement and specify the bases (and, optionally, the type) of the new object. This always creates a type object.
  • To create a new object using instantiation, we use the call operator (()) on the type object we want to use. This may create a type or a non-type object, depending on which type object was used.
  • Some non-type objects can be created using special Python syntax. For example, [1, 2, 3] creates an instance of <type 'list'>.
  • Internally, Python always uses a type object to create a new object. The new object created is an instance of the type object used. Python determines the type object from a class statement by looking at the bases specified, and finding their types.
  • issubclass(A,B) (testing for superclass-subclass relationship) returns True iff:
    1. B is in A.__bases__, or
    2. issubclass(Z,B) is true for any Z in A.__bases__.

     

  • isinstance(A,B) (testing for type-instance relationship) returns True iff:
    1. B is A.__class__, or
    2. issubclass(A.__class__,B) is true.

     

  • Squasher is really a python. (Okay, that wasn’t mentioned before, but now you know.)

More Types to Play With

The following example shows how to discover and experiment with built-in types.

Example 3.1. More built-in 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 The types module contains many built-in types.
2 Some well known types have another name as well.
3 def creates a function object.
4 The type of a function object is types.FunctionType
5 Some built-in types can be subclassed.
6 Some cannot.
7 More types than you can shake a stick at.

What’s the Point, Anyway?

So we can create new objects with any relationship we choose, but what does it buy us?
The relationships between objects determine how attribute access on the object works. For example, when we sayobjectname.attributename, which object do we end up with? It all depends on objectname, its type, and its bases (if they exist).
Attribute access mechanisms in Python are explained in the second book of this series: Python Attributes and Methods.

Classic Classes

This is a note about classic classes in Python. We can create classes of the old (pre 2.2) kind by using a plain class statement.

Example 3.2. Examining classic classes

>>> 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 A class statement specifying no bases creates a classic class Remember that to create a new-style class you must specify object as the base (although this is not required in Python 3.0 since new-style classes are the default). Specifying only classic classes as bases also creates a classic class. Specifying both classic and new-style classes as bases create a new-style class.
2 Its type is an object we haven’t seen before (in this book).
3 The type of classic classes is an object called types.ClassType.
4 5 It looks and smells like just another type object.

The types.ClassType object is in some ways an alternative <type 'type'>. Instances of this object (classic classes) are types themselves. The rules of attribute access are different for classic classes and new-style classes. Thetypes.ClassType object exists for backward compatibility and may not exist in future versions of Python. Other sections of this book should not be applied to classic classes.
Comment on this book here: discussion page. I appreciate feedback!
That’s all, folks!

Chapter 4. Stuff You Should Have Learnt Elsewhere

Object-Oriented Relationships

Can Skim Section

This oddly placed section explains the type-instance and supertype-subtype relationships, and can be safely skipped if the reader is already familiar with these OO concepts. Skimming over the rules below might be useful though.

While we introduce many different objects, we only use two kinds of relationships (Figure 4.1, “Relationships”):

  • is a kind of (solid line): Known to the OO folks as specialization, this relationship exists between two objects when one (the subclass) is a specialized version of the other (the superclass). A snake is a kind of reptile. It has all the traits of a reptile and some specific traits which identify a snake.Terms used: subclass ofsuperclass of and superclass-subclass.
  • is an instance of (dashed line): Also known as instantiation, this relationship exists between two objects when one (the instance) is a concrete example of what the other specifies (the type). I have a pet snake named Squasher. Squasher is an instance of a snake.Terms used: instance oftype oftype-instance and class-instance.

Note that in plain English, the term ‘is a’ is used for both of the above relationships. Squasher is a snake and snake is a reptile are both correct. We, however, use specific terms from above to avoid any confusion.

Figure 4.1. Relationships

Relationships


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

If X is an instance of A, and A is a subclass of B, then X is an instance of B as well.

Dashed Arrow Down Rule

If B is an instance of M, and A is a subclass of B, then A is an instance of M as well.

In other words, the head end of a dashed arrow can move up a solid arrow, and the tail end can move down (shown as 2a and 2b in Figure 4.2, “Transitivity of Relationships” respectively). These properties can be directly derived from the definition of the superclass-subclass relationship.

Figure 4.2. Transitivity of Relationships

Transitivity of Relationships


Applying Dashed Arrow Up Rule, we can derive the second statement from the first:

  1. Squasher is an instance of snake (or, the type of Squasher is snake).
  2. Squasher is an instance of reptile (or, the type of Squasher is reptile).

Earlier we said that an object has exactly one type. So how does Squasher have two? Note that although both statements are correct, one is more correct (and in fact subsumes the other). In other words:

  • Squasher.__class__ is snake. (In Python, the __class__ attribute points to the type of an object).
  • Both isinstance(Squasher, snake) and isinstance(Squasher, reptile) are true.

 
A similar rules exists for the superclass-subclass relationship.

Combine Solid Arrows Rule

If A is a subclass of B, and B is a subclass of C, then A is a subclass of C as well.

A snake is a kind of reptile, and a reptile is a kind of animal. Therefore a snake is a kind of animal. Or, in Pythonese:

  • snake.__bases__ is (reptile,). (The __bases__ attribute points to a tuple containing superclasses of an object).
  • Both issubclass(snake, reptile) and issubclass(snake, animal) are true.

Note that it is possible for an object to have more than one base.

Related Documentation

[descrintro] Unifying types and classes in Python 2.2Guido van Rossum.
[pep-253] Subclassing Built-in TypesGuido van Rossum.

Leave a Reply