← 学习库 Think Python (2e) · 中英对照 目录

Appendix C  Lumpy 附录 C Lumpy

本页译自 Think Python 2e(Allen B. Downey)· Appendix C Lumpy。代码块保留英文原文不翻译;正文段段对照,中文块可用右下角按钮隐藏。

Throughout the book, I have used diagrams to represent the state of running programs.

全书各处,我都用图示来表示运行中的程序的状态。

In Section 2.2, we used a state diagram to show the names and values of variables. In Section 3.10 I introduced a stack diagram, which shows one frame for each function call. Each frame shows the parameters and local variables for the function or method. Stack diagrams for recursive functions appear in Section 5.9 and Section 6.5.

在 2.2 节,我们用状态图展示了变量的名字和值。在 3.10 节我介绍了栈图,它为每次函数调用显示一个栈帧。每个栈帧展示了该函数或方法的形参与局部变量。递归函数的栈图见 5.9 节和 6.5 节。

Section 10.2 shows what a list looks like in a state diagram, Section 11.4 shows what a dictionary looks like, and Section 12.6 shows two ways to represent tuples.

10.2 节展示了列表在状态图中的样子,11.4 节展示了字典的样子,12.6 节展示了表示元组的两种方式。

Section 15.2 introduces object diagrams, which show the state of an object’s attributes, and their attributes, and so on. Section 15.3 has object diagrams for Rectangles and their embedded Points. Section 16.1 shows the state of a Time object. Section 18.2 has a diagram that includes a class object and an instance, each with their own attributes.

15.2 节引入对象图,它展示一个对象及其属性(以及属性的属性……)的状态。15.3 节有 Rectangle 及其内嵌 Point 的对象图。16.1 节展示了一个 Time 对象的状态。18.2 节有一张图,包含一个类对象和一个实例,各自带有自己的属性。

Finally, Section 18.8 introduces class diagrams, which show the classes that make up a program and the relationships between them.

最后,18.8 节引入类图,它展示构成一个程序的各个类以及它们之间的关系。

These diagrams are based on the Unified Modeling Language (UML), which is a standardized graphical language used by software engineers to communicate about program design, especially for object-oriented programs.

这些图示基于统一建模语言(UML),这是软件工程师用来交流程序设计的、标准化的图形化语言,尤其用于面向对象程序。

UML is a rich language with many kinds of diagrams that represent many kinds of relationship between objects and classes. What I presented in this book is a small subset of the language, but it is the subset most commonly used in practice.

UML 是一种丰富的语言,拥有多种图示类型,用来表示对象与类之间的多种关系。本书所介绍的只是这门语言的一小部分,但却是实践中最常用的那一部分。

The purpose of this appendix is to review the diagrams presented in the previous chapters, and to introduce Lumpy. Lumpy, which stands for “UML in Python,” with some of the letters rearranged, is part of Swampy, which you already installed if you worked on the case study in Chapter 4 or Chapter 19, or if you did Exercise 4,

本附录的目的是回顾前面各章出现的图示,并介绍 Lumpy。Lumpy 是「UML in Python」的意思(字母做了些重排),它是 Swampy 的一部分;如果你做过第 4 章或第 19 章的案例研究,或者做过习题 4,就已经安装过它了。

Lumpy uses Python’s inspect module to examine the state of a running program and generate object diagrams (including stack diagrams) and class diagrams.

Lumpy 使用 Python 的 inspect 模块来检查运行中程序的状态,并生成对象图(含栈图)和类图。

C.1 State diagram C.1 状态图

Figure C.1: State diagram generated by Lumpy.

图 C.1:由 Lumpy 生成的状态图(原书插图未收录)

Here’s an example that uses Lumpy to generate a state diagram.

下面是一个用 Lumpy 生成状态图的例子。
inspect06

The first line imports the Lumpy class from inspect07. If you don’t have Swampy installed as a package, make sure the Swampy files are in Python’s search path and use this import statement instead:

第一行从 inspect09 导入 Lumpy 类。如果你没有把 Swampy 当作包安装,请确保 Swampy 文件在 Python 的搜索路径中,并改用下面这条 import 语句:
inspect11

The next lines create a Lumpy object and make a “reference” point, which means that Lumpy records the objects that have been defined so far.

接下来的几行创建了一个 Lumpy 对象并设立一个「引用」点,意思是 Lumpy 会记录到目前为止已定义的对象。

Next we define new variables and invoke inspect14, which draws the objects that have been defined since the reference point, in this case inspect, n and n0.

接着我们定义新的变量并调用 inspect18,它会绘制出自引用点以来定义的对象,此例中就是 inspectnn0。

Figure C.1 shows the result. The graphical style is different from what I showed earlier; for example, each reference is represented by a circle next to the variable name and a line to the value. And long strings are truncated. But the information conveyed by the diagram is the same.

图 C.1 显示了结果。图形风格与我之前展示的有所不同;例如,每个引用由一个紧挨变量名的圆圈和一条指向值的连线表示。长字符串会被截断。但图所传达的信息是一样的。

The variable names are in a frame labeled inspect22, which indicates that these are module-level variables, also known as global.

变量名位于一个标记为 inspect23 的栈帧中,这表明它们是模块级变量,也就是全局变量。

You can download this example from inspect24. Try adding some additional assignments and see what the diagram looks like.

你可以从 inspect25 下载这个例子。试着添加一些额外的赋值语句,看看图会变成什么样子。

C.2 Stack diagram C.2 栈图

Figure C.2: Stack diagram.

图 C.2:栈图(原书插图未收录)

Here’s an example that uses Lumpy to generate a stack diagram. You can download it from inspect26.

下面是一个用 Lumpy 生成栈图的例子。你可以从 inspect27 下载它。
inspect28

Figure C.2 shows the result. Each frame is represented with a box that has the function’s name outside and variables inside. Since this function is recursive, there is one frame for each level of recursion.

图 C.2 显示了结果。每个栈帧用一个方框表示:函数名在框外,变量在框内。由于这个函数是递归的,递归的每一层都有一个栈帧。

Remember that a stack diagram shows the state of the program at a particular point in its execution. To get the diagram you want, sometimes you have to think about where to invoke inspect29.

要记住,栈图展示的是程序在执行过程中某个特定时刻的状态。为了得到你想要的图,有时需要琢磨一下该在哪里调用 inspect30。

In this case I invoke inspect31 after executing the base case of the recursion; that way the stack diagram shows each level of the recursion. You can call inspect32 more than once to get a series of snapshots of the program’s execution.

在这里,我在执行完递归的基础情形之后调用 inspect33;这样栈图就能显示出递归的每一层。你可以多次调用 inspect34,从而得到程序执行过程的一系列快照。

C.3 Object diagrams C.3 对象图

Figure C.3: Object diagram.

图 C.3:对象图(原书插图未收录)

This example generates an object diagram showing the lists from Section 10.1. You can download it from inspect35.

这个例子生成一张对象图,展示 10.1 节的列表。你可以从 inspect36 下载它。
inspect37

Figure C.3 shows the result. Lists are represented by a box that shows the indices mapping to the elements. This representation is slightly misleading, since indices are not actually part of the list, but I think they make the diagram easier to read. The empty list is represented by an empty box.

图 C.3 显示了结果。列表用一个方框表示,方框中显示索引到元素的映射。这种表示法有点误导人,因为索引其实并不是列表的一部分,但我认为它们能让图更易读。空列表用一个空方框表示。

Figure C.4: Object diagram.

图 C.4:对象图(原书插图未收录)

And here’s an example showing the dictionaries from Section 11.4. You can download it from inspect38.

这里有一个例子,展示 11.4 节的字典。你可以从 inspect39 下载它。
inspect40

Figure C.4 shows the result. n000 is a dictionary that maps from characters (single-letter strings) to integers; inspect maps from integers to lists of strings.

图 C.4 显示了结果。n000 是一个字典,它从字符(单字母字符串)映射到整数;inspect 从整数映射到字符串列表。

Figure C.5: Object diagram.

图 C.5:对象图(原书插图未收录)

This example generates an object diagram for Point and Rectangle objects, as in Section 15.6. You can download it from inspect45.

这个例子为 Point 和 Rectangle 对象生成一张对象图,如同 15.6 节那样。你可以从 inspect46 下载它。
inspect47

Figure C.5 shows the result. inspect48 make a shallow copy, so n00 and n000 have their own Lumpy and import, but they share the same embedded Point object. This kind of sharing is usually fine with immutable objects, but with mutable types, it is highly error-prone.

图 C.5 显示了结果。inspect53 做的是浅拷贝,因此 n00 和 n000 各有自己的 Lumpyimport,但它们共享同一个内嵌的 Point 对象。这种共享对不可变对象通常没问题,但对可变类型来说则极易出错。

C.4 Function and class objects C.4 函数与类对象

Figure C.6: Object diagram.

图 C.6:对象图(原书插图未收录)

When I use Lumpy to make object diagrams, I usually define the functions and classes before I make the reference point. That way, function and class objects don’t appear in the diagram.

我用 Lumpy 制作对象图时,通常会在设立引用点之前先把函数和类定义好。这样,函数和类对象就不会出现在图中。

But if you are passing functions and classes as parameters, you might want them to appear. This example shows what that looks like; you can download it from inspect58.

但如果你要把函数和类作为参数传递,可能希望它们出现在图中。这个例子展示了那种情形;你可以从 inspect59 下载它。
inspect60

Figure C.6 shows the result. Since we invoke inspect61 inside a function, we get a stack diagram with a frame for the module-level variables and for the invocation of inspect62.

图 C.6 显示了结果。由于我们在函数内部调用 inspect63,我们得到一张栈图,其中既有模块级变量的栈帧,也有 inspect64 调用的栈帧。

At the module level, Lumpy and inspect66 refer to class objects (which have type n000); inspect68 refers to a function object.

在模块层级上,Lumpyinspect70 指向类对象(其类型为 n000);inspect72 指向一个函数对象。

This diagram might clarify two points of common confusion: (1) the difference between the class object, Lumpy, and the instance of Point, n00, and (2) the difference between the function object created when inspect75 is defined, and the frame created with it is called.

这张图或许能澄清两个常见的混淆点:(1) 类对象 Lumpy 与 Point 的实例 n00 之间的区别;(2) 定义 inspect78 时创建的函数对象,与调用它时创建的栈帧之间的区别。

C.5 Class Diagrams C.5 类图

Figure C.7: Class diagram.

图 C.7:类图(原书插图未收录)

Figure C.8: Class diagram.

图 C.8:类图(原书插图未收录)

Although I distinguish between state diagrams, stack diagrams and object diagrams, they are mostly the same thing: they show the state of a running program at a point in time.

尽管我区分了状态图、栈图和对象图,但它们大体上是同一回事:它们都展示运行中的程序在某个时刻的状态。

Class diagrams are different. They show the classes that make up a program and the relationships between them. They are timeless in the sense that they describe the program as a whole, not any particular point in time. For example, if an instance of Class A generally contains a reference to an instance of Class B, we say there is a “HAS-A relationship” between those classes.

类图则不同。它展示构成一个程序的各个类以及它们之间的关系。它是「无时间性」的,意思是它描述的是程序的整体,而非任何特定时刻。例如,如果 A 类的实例通常含有一个指向 B 类实例的引用,我们就说这两个类之间存在「HAS-A 关系」(包含关系)。

Here’s an example that shows a HAS-A relationship. You can download it from inspect79.

下面是一个展示 HAS-A 关系的例子。你可以从 inspect80 下载它。
inspect81

Figure C.7 shows the result. Each class is represented with a box that contains the name of the class, any methods the class provides, any class variables, and any instance variables. In this example, inspect82 and Lumpy have instance variables, but no methods or class variables.

图 C.7 显示了结果。每个类用一个方框表示,方框中包含类名、该类提供的任何方法、任何类变量以及任何实例变量。在这个例子中,inspect84 和 Lumpy 都有实例变量,但没有方法或类变量。

The arrow from inspect86 to Lumpy shows that Rectangles contain an embedded Point. In addition, inspect88 and Lumpy both inherit from import, which is represented in the diagram with a triangle-headed arrow.

inspect91 指向 Lumpy 的箭头表明 Rectangle 含有一个内嵌的 Point。此外,inspect93 和 Lumpy 都继承自 import,这在图中用一个三角箭头表示。

Here’s a more complex example using my solution to Exercise 6. You can download the code from inspect96; you will also need inspect97.

下面是一个更复杂的例子,使用了我对习题 6 的解答。你可以从 inspect98 下载代码;你还需要 inspect99。
import100

Figure C.8 shows the result. import101 inherits from n000, which inherits from n000. Both n000 and import105 have Cards.

图 C.8 显示了结果。import106 继承自 n000,而 n000 又继承自 n000。n000 和 import111 都含有 Card。

This diagram does not show that n000 also has cards, because in the program there are no instances of Hand. This example demonstrates a limitation of Lumpy; it only knows about the attributes and HAS-A relationships of objects that are instantiated.

这张图没有显示 n000 也含有 card,因为程序中并没有 n000 的实例。这个例子说明了 Lumpy 的一个局限:它只知道那些被实例化的对象的属性和 HAS-A 关系。