As usual, create a directory to hold today's activities:
$ mkdir ~/cs170/labs/lab9 $ cd ~/cs170/labs/lab9
We now understand how classes can represent our own data types. This is incredibly neat, and even allows for the efficient reuse of code. However, there are some instance where your current knowledge of classes would cause your code to not be very reusable. For example, what if something doesn't fit exactly into the templates we've created for our objects? One mechanism to fix this problem is inheritance, which allows us to specify the relationships between classes.
One of the more classical examples of Inheritance is describing animals. There is a well known hierarchy of animals, based off of genus, species, phylum, etc. However, that can be a little bit complicated and overwhelming. So, we'll focus on one common type of animal: dogs.
This is a very simplistic, directed, and less that useful example of inheritance. Hopefully it give you a better understanding of the syntax and the meaning behind inheritance.
The file dog.py contains a declaration for a
Dog
class. Save this file to your directory and study it. Notice what
instance variables and methods are provided. The file also contains
some code that runs the actual program. Make sure you understand
what it does, and how.
One use of inheritance is to change the behavior of specific
methods. Create a a class called Dog
. Override the speak method
of the Dog class by defining a method in the
Pomeranian
class with the same method signature. The
method should print something typical of a Pomeranian.
Modify the program to add statements to create an instance of the
Pomeranian class and make it speak (do not remove Spot). Run
the program. Both dogs should speak something different because
both classes have different bodies for the speak
method. Notice that you did not define the __init__
method for the Pomeranian
class and yet you are still
able to call it because it was inherited from the Dog
class.
In addition to replacing the behavior of a method in the parent
class it is also possible to extend the behavior of a method in the
parent class. Create a class
called Labrador
in the same file that also extends
Dog
.
Add a second parameter to the __init__
method that
specifies the color of the lab and store the lab's color in an
attribute. Again override the speak method with something
typical of a lab. Also include something about the lab's color in
the speak
print statement.
Modify your program by adding statements to create a
Labrador. Be sure to call the constructor method that
specifies the name and the color. Also add a statement to make it
speak. Run the program. The dog and Pomeranian should speak, but
there should be an error with the lab. The name
attribute is not defined because the Dog
class's __init__
method was overridden in the
Labrador class. To fix this add a call to the
Dog class's __init__
method by
using built-in method super
by adding the following
statement to the Labrador's __init__
method:
super().__init__(name)
Run the dog_test program to verify that the program now works.
>>> spot = Dog("Spot") >>> spot.speak() Spot says Woof. >>> bandit = Pomeranian("Bandit") >>> bandit.speak() Bandit says Squeak. >>> spike = Labrador("Spike", "Blond") Spike, the Blond Labrador says Bark.
Inheritance also allows us to abstract the core components of a classification of objects, to make our code more general. For example, in Tkinter the same pieces of data really represent most of the things that can be drawn on the screen.
Today, you will make a class structure that will allow you to represent an arbitrary shape. You will then draw those shapes to a Tk canvas.
Again, I would like you to start on paper. Have either myself or one of the lab assistants check your paper work before you get started coding. You should try the paper pseudo-code before you look at the hint. The hint is there if you are completely lost, however.
In a file called drawing_shapes.py, create a class called
Shape
. This class should have all the attributes
necessary to draw a generic shape, as well as any methods that you can
use to put the generic shapes onto a tk window. For now, this shape
can be drawn as just a dot on the canvas.
You should have at least 3 shapes that inherit the generic Shape
class: Circle
, Square
, and
Triangle
. You should use the currently defined methods
in the Shape class when appropriate, and override methods when you
need to.
Use these three shapes to create an interesting drawing on your Tk window.
At the very least, your Shape class needs an attribute for the canvas, as well as the location of the shape on the canvas. Depending on how creative you get, you might also want a fill color.
You also need to be able to draw the shape, so you will at least need a method for that. For this generic shape, just draw a dot at the location stored in the Shape class.
Your other shapes need a slight modification to the Shape
constructor. For example, Circle
needs a radius
for drawing, whereas Triangle
and
Square
need a side length in order to draw.
Override the constructor, but don't forget to call super's
constructor as well!
You will also need to override the draw method to handle drawing the new shapes.
Right now, anyone with programming experience can probably draw using your program. However, that really limits the amount of users you can have with this setup. A better setup would allow users to click on the canvas to draw.
Add to the functionality to allow users to draw by clicking on the canvas. You will need some mechanism that allows users to select which shape they want to draw next. You can either bind keyboard listeners that select the shapes, or you can explore the Tk button widget to allow users to select a shape based on mouse clicks as well.
You may need to alter your classes slightly for this, since it will be hard to determine the size of the shapes to get drawn. Unless...
If you implement a mouse motion listener properly, you can actually allow for a shape to get re-sized as they get drawn. You just have to make sure that you remove the previous shape that was drawn when you redraw the new shape.
This one behaves a little bit funny. You will have to register the mouse motion listener on a mouse press, and "unregister" the listener on mouse release. Take a look at the tkinter documentation to see how this works.
Again, this might require some slight modifications to your classes.
When you have finished, create a tar file of your lab9
directory. To create a tar file, execute the following commands:
cd ~/cs170/labs tar czvf lab9.tgz lab9/
To submit your activity, go to inquire.roanoke.edu. You should
see an available assignment called Lab Assignment 9
.
Make sure you include a header listing the authors of the file.