Fruitful Graphical Recursion and Introduction to Classes¶
Today we will look at a few more examples of graphical recursion. Recall that fruitful functions contain explicit return values. In fruitful graphical recursion, we recursively calculate values as we recursively draw our pictures.
After wrapping up recursion, we will move on to discussing how to define our own classes and objects in Python.
from turtle import *
Fruitful Nested Circles¶
Last time we drew a pretty picture involving nested circles. Suppose we wanted to calculate the number of circles drawn of each color. We can accomplish this by making our nestedCircles
function fruitful.
def drawDisc(radius, color):
# put the pen down
down()
# set the color
fillcolor(color)
# draw the circle
begin_fill()
circle(radius)
end_fill()
# put the pen up
up()
def nestedCircles(radius, minRadius, colorOut, colorAlt):
if radius < minRadius:
# since we do not draw any circles, we return (0,0)
return (0,0)
else:
# contribute to the solution
# note that we are drawing one circle with color colorOut
drawDisc(radius, colorOut)
# save half of radius
halfRadius = radius/2
# position the turtle at the right place
lt(90); fd(halfRadius); rt(90); fd(halfRadius)
# draw right subcircle(s) recursively
# we need to save the resulting tuple
# order of resulting tuple values corresponds to order of arguments
rightColorAlt, rightColorOut = nestedCircles(halfRadius, minRadius, colorAlt, colorOut)
# position turtle for left subcircle
bk(radius)
# draw left subcircle recursively
leftColorAlt, leftColorOut = nestedCircles(halfRadius, minRadius, colorAlt, colorOut)
# bring turtle back to start position
fd(halfRadius); lt(90); bk(halfRadius); rt(90)
# finally, let's return the total sum of the circles
# values should be ordered colorOut, colorAlt
return (rightColorOut + leftColorOut + 1, rightColorAlt + leftColorAlt)
setup(1200, 1200)
reset()
speed(0)
up()
goto(0, -300)
down()
print(nestedCircles(300, 30, "gold", "purple"))
hideturtle()
(5, 10)
Recursive Trees¶
Before moving on, let’s look at one more recursive example that doesn’t involve circles. Suppose we want to draw recursive tres.
# trunkLen is the trunk length of the main (vertical) trunk
# angle is the branching angle, or the angle between a trunk and its right/left branch
# shrinkFactor specifies how much smaller each subsequent branch is in length
# minLength is the minimum branch length in our tree
def tree(trunkLen, angle, shrinkFactor, minLength):
if trunkLen < minLength:
pass # do nothing
else:
# Draw the trunk
fd(trunkLen)
# Turn and draw the right subtree.
rt(angle)
newTrunkLen = trunkLen*shrinkFactor
tree(newTrunkLen, angle, shrinkFactor, minLength)
# Turn and draw the left subtree.
lt(angle * 2)
tree(newTrunkLen, angle, shrinkFactor, minLength)
# Return to starting position
up(); rt(angle); bk(trunkLen); down()
# test the tree function
setup(1200, 1200)
reset()
speed(0)
up()
goto(0, -300)
down()
pensize(4)
# start turtle facing north
lt(90)
tree(100, 45, 0.5, 5)
hideturtle()
Exercise: Can you make this function fruitful and return the sum of the lengths of all of the branches drawn?
Classes and Methods¶
Python supports many different kinds of data:
1234 (int), 3.14 (float), “Hello” (str) [1, 5, 7, 11, 13] (list), {“CA”: “California”, “MA”: “Massachusetts”} (dict)
Each of these is an object, and every object has:
a type
an internal data representation (primitive or composite)
a set of methods for interaction with the object
Classes allow us to define our own objects and data types in Python. After defining a class, we can create an instance of a class and interact with that instance using methods.
All methods belong to a specific class, and are defined within that class. A method’s purpose is to provide a way to access/manipulate objects (or specific instances of the class).
The first parameter in the method definition is the reference to the calling instance (self
). When invoking methods, this reference is provided implicitly.
Simple Class and Method¶
Let’s define a simple class with a single method that prints “Hello” and see how we can call the method on an instance of the class.
class A:
"""Class to test the use of methods"""
def greeting(self):
print("Hello")
a = A()
a.greeting()
Hello
Digging Deeper: Self¶
Lets try to understand what the purpose of the parameter self
by using the python function id()
.
Recall that id(obj)
displays the unique identifier to the object. You can think of this number as the address in memory this object is stored.
Let us rewrite class A
to print the id
of self.
class A:
"""Class to test the use of methods"""
def greeting(self):
print("Hello, object with ID", id(self))
obj = A()
obj.greeting()
Hello, object with ID 5119842528
id(obj)
5119842528