← 学习库 Think Python 2e 目录

Chapter 23

> 来源: Think Python 2e (Allen B. Downey)

> 原页: https://greenteapress.com/thinkpython/html/thinkpython023.html

\

[插图缺失:thinkpython022.html]
[ [](thinkpython024.html)

------------------------------------------------------------------------

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.

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.

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.

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

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

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 uses Python’s inspect module to examine the state of a running program and generate object diagrams (including stack diagrams) and class diagrams.

C.1   State diagram


[插图缺失:thinkpython030.png]

Figure C.1: State diagram generated by Lumpy.


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

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

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.

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

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.

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

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

C.2   Stack diagram


[插图缺失:thinkpython031.png]

Figure C.2: Stack diagram.


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

inspect18

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.

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

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

C.3   Object diagrams


[插图缺失:thinkpython032.png]

Figure C.3: Object diagram.


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

inspect23

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.


[插图缺失:thinkpython033.png]

Figure C.4: Object diagram.


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

inspect25

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.


[插图缺失:thinkpython034.png]

Figure C.5: Object diagram.


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

inspect29

Figure C.5 shows the result. inspect30 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.4   Function and class objects


[插图缺失:thinkpython035.png]

Figure C.6: Object diagram.


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.

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

inspect36

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

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

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 inspect45 is defined, and the frame created with it is called.

C.5   Class Diagrams


[插图缺失:thinkpython036.png]

Figure C.7: Class diagram.



[插图缺失:thinkpython037.png]

Figure C.8: Class diagram.


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.

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

inspect47

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, inspect48 and Lumpy have instance variables, but no methods or class variables.

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

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

inspect57

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

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.

Contribute

If you would like to make a contribution to support my books, you can use the button below. Thank you!

Pay what you want:

Small $1.00 USD Medium $5.00 USD Large $10.00 USD X-Large $20.00 USD XX-Large $50.00 USD

Are you using one of our books in a class?

We'd like to know about it. Please consider filling out this short survey.


------------------------------------------------------------------------

\

[插图缺失:thinkpython022.html]
[ [](thinkpython024.html)

---

← Chapter 22Chapter 24 →