Skip to content

Latest commit

 

History

History
170 lines (116 loc) · 9.81 KB

第八章-对象的引用、可变性和回收.md

File metadata and controls

170 lines (116 loc) · 9.81 KB

CHAPTER 8 Object References, Mutability, and Recycling

‘You are sad,’ the Knight said in an anxious tone: ‘let me sing you a song to comfort you. [...] The name of the song is called “HADDOCKS’ EYES”.’ ‘Oh, that’s the name of the song, is it?’ Alice said, trying to feel interested. ‘No, you don’t understand,’ the Knight said, looking a little vexed. ‘That’s what the name is CALLED. The name really IS “THE AGED AGED MAN."’ (adapted from Chapter VIII. ‘It’s my own Invention’). — Lewis Carroll Through the Looking-Glass, and What Alice Found There

Alice and the Knight set the tone of what we will see in this chapter. The theme is the distinction between objects and their names. A name is not the object; a name is a separate thing.

We start the chapter by presenting a metaphor for variables in Python: variables are labels, not boxes. If reference variables are old news to you, the analogy may still be handy if you need to explain aliasing issues to others.

We then discuss the concepts of object identity, value, and aliasing. A surprising trait of tuples is revealed: they are immutable but their values may change. This leads to a discussion of shallow and deep copies. References and function parameters are our next theme: the problem with mutable parameter defaults and the safe handling of mutable arguments passed by clients of our functions.

The last sections of the chapter cover garbage collection, the del command, and how to use weak references to “remember” objects without keeping them alive.

This is a rather dry chapter, but its topics lie at the heart of many subtle bugs in real Python programs.

Let’s start by unlearning that a variable is like a box where you store data.

Variables Are Not Boxes 变量不是个盒子

In 1997, I took a summer course on Java at MIT. The professor, Lynn Andrea Stein— an award-winning computer science educator who currently teaches at Olin College of Engineering—made the point that the usual “variables as boxes” metaphor actually hinders the understanding of reference variables in OO languages. Python variables are like reference variables in Java, so it’s better to think of them as labels attached to objects.

Example 8-1 is a simple interaction that the “variables as boxes” idea cannot explain. Figure 8-1 illustrates why the box metaphor is wrong for Python, while sticky notes provide a helpful picture of how variables actually work.

例子8-1是一个简单的“变量即盒子”思想不能解释的交互命令。图表8-1

Example 8-1. Variables a and b hold references to the same list, not copies of the list

>>>a=[1,2,3] 
>>>b=a
>>> a.append(4) 
>>> b
[1, 2, 3, 4]

img

Figure 8-1. If you imagine variables are like boxes, you can’t make sense of assignment in Python; instead, think of variables as sticky notes—Example 8-1 then becomes easy to explain

图表8-1. 如果你想象变量跟盒子一样,你就无法理解Python中的赋值;相反,

Prof. Stein also spoke about assignment in a very deliberate way. For example, when talking about a seesaw object in a simulation, she would say: “Variable s is assigned to the seesaw,” but never “The seesaw is assigned to variable s.” With reference variables, it makes much more sense to say that the variable is assigned to an object, and not the other way around. After all, the object is created before the assignment. Example 8-2 proves that the righthand side of an assignment happens first.

Stein教授也讲过关于赋值

Example 8-2. Variables are assigned to objects only after the objects are created

例子8-2.变量赋值到对象仅在创建被创建之后。

>>> class Gizmo:
...     def __init__(self):
...         print('Gizmo id: %d' % id(self))
... 
>>> x = Gizmo()
Gizmo id: 4303555472
>>> y = Gizmo() * 10
Gizmo id: 4303555544
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for *: 'instance' and 'int'
>>> dir()
['Gizmo', '__builtins__', '__doc__', '__name__', '__package__', 'x']
  1. The output Gizmo id: ... is a side effect of creating a Gizmo instance.
  2. Multiplying a Gizmo instance will raise an exception.
  3. Here is proof that a second Gizmo was actually instantiated before the multiplication was attempted.
  4. But variable y was never created, because the exception happened while the right- hand side of the assignment was being evaluated.

Tips 提示

To understand an assignment in Python, always read the right- hand side first: that’s where the object is created or retrieved. Af‐ ter that, the variable on the left is bound to the object, like a label stuck to it. Just forget about the boxes.

要理解Python中赋值,你要一直从右边读起来:此处为对象被创建或者重新取回。之后,左边的变量被绑定到对象,就像粘上去的标签一样。所以,把盒子给忘掉吧。

Because variables are mere labels, nothing prevents an object from having several labels assigned to it. When that happens, you have aliasing, our next topic.

因为变量仅仅是标签而已,没有什么能阻止一个对象给自己使用多个标签。

Identity, Equality, and Aliases

Lewis Carroll is the pen name of Prof. Charles Lutwidge Dodgson. Mr. Carroll is not only equal to Prof. Dodgson: they are one and the same. Example 8-3 expresses this idea in Python.

Lewis Carroll是Charles Lutwidge Dodgson教授的笔名。Carroll不仅等于教授Dodgson:它们就是同一个完全一样的东西。例子8-3表现了Python中的这种思想。

Example 8-3. charles and lewis refer to the same object
例子8-3. charles和lewis引用了相同的对象。

>>> charles = {'name': 'Charles L. Dodgson', 'born': 1832}
>>> lewis = charles  #1
>>> lewis is charles
True
>>> id(charles), id(lewis) #2
(4522426448, 4522426448)
>>> lewis['balance'] = 950 #3
>>> charles
{'born': 1832, 'balance': 950, 'name': 'Charles L. Dodgson'}
  1. lewis is an alias for charles.

  2. The is operator and the id function confirm it.

  3. Adding an item to lewis is the same as adding an item to charles.

  4. lewis是一个charles的别名。

  5. is运算符和id函数对它进行确认。

However, suppose an impostor—let’s call him Dr. Alexander Pedachenko—claims he is Charles L. Dodgson, born in 1832. His credentials may be the same, but Dr. Pedachenko is not Prof. Dodgson. Figure 8-2 illustrates this scenario.

Flowers Figure 8-2. charles and lewis are bound to the same object; alex is bound to a separate object of equal contents

Example 8-4 implements and tests the alex object depicted in Figure 8-2.

Example 8-4. alex and charles compare equal, but alex is not charles

>>> alex = {'name': 'Charles L. Dodgson', 'born': 1832, 'balance': 950}  #1
>>> alex == charles #2 
True
>>> alex is not charles #3
True
  1. alex refers to an object that is a replica of the object assigned to charles.
  2. The objects compare equal, because of the __eq__ implementation in the dict class.
  3. But they are distinct objects. This is the Pythonic way of writing the negative identity comparison: a is not b.

Example 8-3 is an example of aliasing. In that code, lewis and charles are aliases: two variables bound to the same object. On the other hand, alex is not an alias for charles: these variables are bound to distinct objects. The objects bound to alex and charles have the same value—that’s what == compares—but they have different iden‐ tities.

例子8-3是一个

In The Python Language Reference, “3.1. Objects, values and types” states:

Every object has an identity, a type and a value. An object’s identity never changes once it has been created; you may think of it as the object’s address in memory. Theisoperator compares the identity of two objects; the id() function returns an integer representing its identity.

The real meaning of an object’s ID is implementation-dependent. In CPython, id() returns the memory address of the object, but it may be something else in another Python interpreter. The key point is that the ID is guaranteed to be a unique numeric label, and it will never change during the life of the object.

In practice, we rarely use the id() function while programming. Identity checks are most often done with the is operator, and not by comparing IDs. Next, we’ll talk about is versus ==.

Choosing Between == and is

The == operator compares the values of objects (the data they hold), while is compares their identities.

We often care about values and not identities, so == appears more frequently than is in Python code.

However, if you are comparing a variable to a singleton, then it makes sense to use is. By far, the most common case is checking whether a variable is bound to None. This is the recommended way to do it:

x is None

And the proper way to write its negation is:

x is not None

The is operator is faster than ==, because it cannot be overloaded, so Python does not have to find and invoke special methods to evaluate it, and computing is as simple as comparing two integer IDs. In contrast, a == b is syntactic sugar for a.__eq__(b). The __eq__ method inherited from object compares object IDs, so it produces the same result as is. But most built-in types override __eq__ with more meaningful implemen‐ tations that actually take into account the values of the object attributes. Equality may involve a lot of processing—for example, when comparing large collections or deeply nested structures.

运算符is快于==,因为它不能够重载,所以Python不能够找到并调用特殊方法以计算它,计算简单到比较两个整数ID。为了对比,a == ba.__eq__(b)的语法糖。__eq__方法继承自