Chapter 25
Classes may also be related to each other through a mechanism called inheritance. When one class inherits from another, it inherits all the state and behavior of the original class, and then has the opportunity to define additional new state and behavior.
The Sierpinski triangle is an interesting mathematical object (a fractal, like the Mandelbrot set) that is constructed by repeatedly removing the middle from a solid triangle.
Listing 25.1: Sierpinski Triangle
1 # sierpinski.py
2
3 from turtle import Turtle, setworldcoordinates, exitonclick
4
5 class SierpinskiTriangle(Turtle):
6 size = 2
7 def __init__(self, n, x, y):
8 Turtle.__init__(self, visible=False)
9 self.n = n
10 self.speed(0)
11 self.penup()
12 self.goto(x, y)
13
14 def draw(self):
15 if self.n == 0:
16 self.begin_fill()
17 for i in range(3):
18 self.forward(SierpinskiTriangle.size)
19 self.left(120)
20 self.end_fill()
21 else:
22 for i in range(3):
23 SierpinskiTriangle(self.n − 1,
24 self.xcor(),
25 self.ycor()).draw()
26 self.forward(SierpinskiTriangle.size ** self.n)
27 self.left(120)
28
29 def main():
30 setworldcoordinates(0, 0, 75, 75)
31 SierpinskiTriangle(5, 5, 5).draw()
32 exitonclick()
33
34 if __name__ == "__main__":
35 main()
If this program takes too long to complete, try reducing the first parameter to the constructor in main().
The turtle module provides both procedural and object-oriented versions of its functionality. Part I only used procedural code (Python functions) because we had not used objects at that point in the course. Listing 25.1 introduces object-oriented turtle module code via the Turtle class. The Turtle class defines turtle objects that draw and move using method calls that are exactly the same as the function calls we used earlier. In fact, the function calls are implemented in the background by calling the corresponding method on a single internal Turtle object. One advantage of using Turtle objects explicitly is that your program can then work with more than one turtle at a time.
Some of the methods available on a Turtle object t are:
t.pendown() |
Start drawing the turtle’s path. |
t.penup() |
Stop drawing the turtle’s path. |
t.dot() |
Draw a dot at current location. |
t.goto(x, y) |
Move to position (x, y). |
t.forward(n) |
Move forward n units. |
t.left(theta) |
Turn left angle theta (default degrees). |
t.xcor() |
Current position’s x coordinate. |
t.ycor() |
Current position’s y coordinate. |
t.speed(s) |
Set speed (1=slow to 10=fast; 0 is “instantly”). |
t.begin_fill() |
Turn filling on. |
t.end_fill() |
Stop filling. |
You can find the description of other methods in the Python library documentation.
When we define a new class using inheritance, the new class inherits all of the state and behavior of the original class, known as the base class. The new class is called an extension of the base class, and it may define additional new state and behavior. Base classes are also known as parent classes or superclasses; extensions are also known as child classes or subclasses.
Inheritance is said to model an “is-a” relationship because an instance of the extension is an instance of the base class.
The syntax to define a class as an extension of a base class in Python is:
class <ClassName>(<BaseClass>):
<body>
Thus, in Listing 25.1, the SierpinskiTriangle class extends the Turtle base class. Because of this, all of the methods defined in the Turtle class are available to be called on any SierpinskiTriangle object. We say that a SierpinskiTriangle object “is a” Turtle. In addition, SierpinskiTriangle objects have additional state and behavior that Turtle objects do not.
If you define an .__init__() method for a class extension, it is usually a good idea to call the base class’s .__init__() method first to make sure that the state defined for the base class is initialized to reasonable values before trying to set additional state for the extension. The syntax to make this call is:
<BaseClass>.__init__(self, <other parameters>)
Recall that objects store data in instance variables (fields) and that the syntax to access a particular object’s field is <object>.<field>. Every object has its own storage for instance variables and thus different objects may store different values in their fields.
Occasionally, it is helpful for a class to store data that is shared among all instances of the class; in this case, a class variable is appropriate. For example, in Listing 25.1, the size variable of the SierpinskiTriangle class is shared by all instances of that class and controls the size of the triangles that are drawn.
There is no special syntax for declaring class variables in Python. Instead, any variable that is assigned a value inside of a class definition but outside all method definitions of the class (as on line 6) is automatically a class variable. The syntax to access the value of a class variable is:
<ClassName>.<variable>
This is analogous to using <object>.<variable> to access an instance variable.
Class variables are public and may be accessed by code outside of the class using the same syntax.
Set p randomly to one of A, B, or C.
Repeat:
Set q randomly to one of A, B, or C.
Set p to the midpoint between p and q.
Put a dot at p.
Describe the result. You do not need to write any classes.
3.18.104.213