00:00:00

Python From Scratch

Notes

What is this course about?

  • Learn Python syntax
  • Learn control structure such as if .. else and for
  • Learn basic data structures such as list and dict
  • Learn how to define and use functions in Python
  • Must have completed the pre-requisite course Bootstrapping Python
  • Will use the turtle library in Jupyter notebook

Notes

Python and Turtle

Notes

Importing a library

Python offers a rich, vast collection of libraries to its users. Some of these libraries are built-in, while others require installation. To use a library, we first need to import it.

1
2
3
4
from turtle import Turtle, setup, clearscreen
setup(width=500, height=500)
clearscreen()
tom = Turtle()

Sometimes you see people import this way:

1
2
3
4
import turtle
turtle.setup(width=500, height=500)
turtle.clearscreen()
tom = turtle.Turtle()
  • In Jupyter notebook, once you imported a library in one cell, the library becomes available to subsequent cell evaluations.

Notes

Tom the Turtle

Tom the Turtle

Notes

Declaring a variable and assigning a value to it

A variable in Python is similar to one in algebra - it holds a value, and can hold any value.

1
tom = Turtle()
  • tom is a variable, = the assignment operator, and Turtle() the value assigned.
  • The Python interpreter understands Turtle only because we imported Turtle in the previous line.
  • The value Turtle() is an object of the Turtle class. An object packs a lot of functionalities inside it.

Notes

Manipulating an object

You make an object do things by calling its methods (or functions).

1
2
3
4
5
tom = Turtle()
tom.forward(100)
tom.right(90)
tom.forward(100)
tom.right(90)
  • forward and right are methods (or functions) of the Turtle class.
  • Methods can have parameters. The forward method's parameter specifies the distance to go. The right method's parameter specifies the degrees of angle to turn.

Notes

The Turtle moves

Turtle Two Sides

Notes

Speeding up the Turtle

1
2
3
4
5
6
7
8
tom = Turtle()
# Sets the speed (0-10) of the turtle
# 1: slow, 5: normal, 10: fast, 0: fastest
tom.speed(0)
tom.forward(100)
tom.right(90)
tom.forward(100)
tom.right(90)
  • Any text following a '#' character is ignored by the Python interpreter. People use '#' to comment their Python code.
  • It's a good practice to comment your code, because it helps others (and future you) understand your code better.

Notes

Exercise: Can you draw a square?

Turtle Square

Notes

Answer:

Note: this is just one of the many possible answers

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
tom = Turtle()
# Sets the speed (0-10) of the turtle
tom.speed(0)

# the bottom side
tom.forward(100)
tom.right(90)

# the right side
tom.forward(100)
tom.right(90)

# the top side
tom.forward(100)
tom.right(90)

# the left side
tom.forward(100)
tom.right(90)

Notes

Using for loop

We can simplify our square drawing with for loop.

1
2
3
for i in (1, 2, 3, 4):
    tom.forward(100)
    tom.right(90)
  • Loop helps you repeat a task easily.
  • The i is called the loop variable - its value is updated at the beginning of each iteration.
  • Did you notice the indentation on line 2 and 3? Indentation tells the Python interpreter exactly which lines are included in the loop.

Notes

Loop variable

Try adding the following line in our square-drawing loop

1
2
3
4
for i in (1, 2, 3, 4):
    tom.write(i)           # <-- add this line
    tom.forward(100)
    tom.right(90)

Notes

The result

Turtle Square Side Labelled

Notes

Exercise: Draw a regular octagon

Hint: use 80 as side length so Tom doesn't fall over the canvas

Turtle Octagon

Notes

Answer:

1
2
3
for i in (1, 2, 3, 4, 5, 6, 7, 8):
    tom.forward(80)
    tom.right(360/8)

We can simplify the answer even further by using range()

1
2
3
for i in range(1, 9):
    tom.forward(80)
    tom.right(360/8)

Notes

Exercise: Draw a circle!

Hint: Can you draw a hexadecagon (16-gon) first? What does the result tell you?

Turtle Circle

Notes

Answer:

1
2
3
for i in range(1, 361):
    tom.forward(1)
    tom.right(1)

Notes

With flying colors - 1

1
2
3
4
tom.color('red')
for i in range(1, 361):
    tom.forward(1)
    tom.right(1)
  • Use Turtle object's .color() method set the pen color.

Notes

How it looks

Turtle Circle color

Notes

With flying colors - 2!

1
2
3
4
5
6
tom.color('red', 'green')
tom.begin_fill()
for i in range(1, 361):
    tom.forward(1)
    tom.right(1)
tom.end_fill()
  • Turtle object's .color() method can also set the fill color.
  • Use Turtle object's .begin_fill() and .end_fill() methods to indicate when filling should begin and end.

Notes

How it looks

Turtle Circle color solid

Notes

Exercise: Draw a star

Turtle Star

Notes

Answer:

1
2
3
for i in range(1, 6):
    tom.forward(200)
    tom.right(180-180/5)

Notes

Adding colors to our star

1
2
3
4
5
6
tom.color('red', 'blue')
tom.begin_fill()
for i in range(1, 6):
    tom.forward(200)
    tom.right(180-180/5)
tom.end_fill()

Notes

Houston, we have a problem!

Due to intersecting lines, Turtle is confused about where to shade

Turtle Star Colored alternating

Notes

Conditional branching

1
2
3
4
5
6
7
8
9
tom.color('red', 'blue')
tom.begin_fill()
for i in range(1, 11):
    tom.forward(80)
    if i % 2 == 1:
        tom.left(36*2)
    else:
        tom.right(180-36)
tom.end_fill()
  • if .. else does one thing or the other, but never both!
  • % is the modulo operator - it gives the remainder of the left operand divided by the right operand.
  • if i is a non-negative integer, how many possible values of i % 2 are there?

Notes

That's solid!

Turtle Star Colored solid

Notes

Exercise: Draw a set of stairs

Turtle Stairs

Notes

Answer:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
for i in range(1, 14):
    tom.forward(20)
    if i < 7:
        if i % 2 == 1:
            tom.left(90)
        else:
            tom.right(90)
    else:
        if i % 2 == 1:
            tom.right(90)
        else:
            tom.left(90)

Notes

Exercise: color top of the stairs red

Turtle Stairs top color

Notes

Answer:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
for i in range(1, 14):
    if i == 7:
        tom.color('red')
    else:
        tom.color('black')
    tom.forward(20)
    if i < 7:
        if i % 2 == 1:
            tom.left(90)
        else:
            tom.right(90)
    else:
        if i % 2 == 1:
            tom.right(90)
        else:
            tom.left(90)

Notes

Break

Notes

Exercise: Draw a house

Turtle House

Notes

Answer:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
tom.fd(100)
tom.lt(120)
tom.fd(100)
tom.lt(120)
tom.fd(100)
tom.lt(30)
tom.fd(100)
tom.lt(90)
tom.fd(100)
tom.lt(90)
tom.fd(100)

Notes

Introducing functions

How to draw several house with minimum effort? The answer: functions.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
def house():
    tom.fd(100)
    tom.lt(120)
    tom.fd(100)
    tom.lt(120)
    tom.fd(100)
    tom.lt(30)
    tom.fd(100)
    tom.lt(90)
    tom.fd(100)
    tom.lt(90)
    tom.fd(100)

house()    # <-- calling (or invoking) the function
  • The above code just defined a function called house.
  • The house function has no parameters, as indicated by the empty ().

Notes

Exercise: draw a townhouse

Turtle Townhouse

Notes

Answer:

1
2
3
house()
tom.rt(90)
house()

Notes

Parameterizing the function

Wouldn't it be nice to draw houses of a different size, using the same function?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
def house(size):
    tom.fd(size)
    tom.lt(120)
    tom.fd(size)
    tom.lt(120)
    tom.fd(size)
    tom.lt(30)
    tom.fd(size)
    tom.lt(90)
    tom.fd(size)
    tom.lt(90)
    tom.fd(size)

house(50)
tom.rt(90)
house(50)

Notes

Smaller townhouse

Turtle Townhouse small

Notes

Exercise: Adding color

Hint: use tom.fillcolor() to set only the fill color.

Turtle Townhouse small

Notes

Answer:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
def house(size, color):
    tom.fillcolor(color)
    tom.begin_fill()
    tom.fd(size)
    tom.lt(120)
    tom.fd(size)
    tom.lt(120)
    tom.fd(size)
    tom.end_fill()
    tom.lt(30)
    tom.fd(size)
    tom.lt(90)
    tom.fd(size)
    tom.lt(90)
    tom.fd(size)

house(50, 'red')               #<- specify parameter by position
tom.rt(90)
house(size=50, color='green')  #<- specify parameter by name
tom.rt(90)
house(color='yellow', size=50) #<- specify parameter by name

Notes

Positional vs Named parameters

1
2
3
4
5
6
7
house(50, 'red')               #<- specify parameter by position

house(size=50, color='green')  #<- specify parameter by name

house(color='yellow', size=50) #<- specify parameter by name

house(50, color='red')         #<- mix 'n match

Notes

Exercise: Creating a neighborhood

Create a function neighborhood, e.g. neighborhood(num_houses=8, house_size=50)

Turtle Neighborhood

Notes

Answer:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
def house(size, color):
  ...
  ...

def neighborhood(house_size, num_houses):
    for i in range(1, num_houses+1):
        house(house_size, color='black')
        tom.rt(90)

# The 3 lines below simply moves the turtle to the left
# so we have room to draw the houses
tom.pu()     #<-- Pen Up, i.e. do not draw when turtle moves
tom.bk(200)  #<-- Backward
tom.pd()     #<-- Pen Down, i.e. draw when turtle moves

neighborhood(num_houses=8, house_size=50)

Notes

Break

Notes

Introducing list

The mayor mandates the 8 houses of this neighborhood be colored with the following colors, in this order: brown, pink, green, orange, purple, red, blue, yellow.

Think for a bit - how do you represent this data of colors?

Python's list can help!

1
2
3
empty_list = []
odd_numbers = [1, 3, 5, 7, 9]
colors = ['brown', 'pink', 'green', 'gray', 'cyan', 'red', 'blue', 'yellow']
  • A list is just a container of data

Notes

List is iterable

List can be used in a for loop:

1
2
3
colors = ['brown', 'pink', 'green', 'gray', 'cyan', 'red', 'blue', 'yellow']
for color in colors:
    print(color + ' is cool!')

List iterable

Notes

List is indexable

List items can be accessed via its position index. Indexing in python is 0-based.

1
2
3
colors = ['brown', 'pink', 'green', 'gray', 'cyan', 'red', 'blue', 'yellow']
for i in range(0, len(colors)):
    print('color at index #' + str(i) + ' is ' + colors[i])

List indexable

  • Use [] to index into a list. Function len() gives the length of a list.

Notes

Exercise: Color a neighborhood to order

Hint: Modify your neighborhood function to accept a house_colors parameter.

Turtle neighborhood color

Notes

Answer:

1
2
3
4
5
6
7
8
9
def neighborhood(house_size, num_houses, house_colors):
    for i in range(0, num_houses):
        house(house_size, color=house_colors[i])
        tom.rt(90)
tom.pu()
tom.bk(200)
tom.pd()
colors = ['brown', 'pink', 'green', 'gray', 'cyan', 'red', 'blue', 'yellow']   
neighborhood(num_houses=8, house_size=50, house_colors=colors)

Notes

Exercise: Simplify previous answer

Can you remove the num_houses parameter, and instead infer the number of houses from the number of colors provided?

Your neighborhood function should now start like this:

1
2
3
def neighborhood(house_size, house_colors):
  ...
  ...

Notes

Answer:

1
2
3
4
5
6
7
8
9
def neighborhood(house_size, house_colors):
    for i in range(0, len(house_colors)):
        house(house_size, color=house_colors[i])
        tom.rt(90)
tom.pu()
tom.bk(200)
tom.pd()
colors = ['brown', 'pink', 'green', 'gray', 'cyan', 'red', 'blue', 'yellow']   
neighborhood(house_size=50, house_colors=colors)

Notes

Break

Notes

The Mayor's problem

Families are moving into the newly constructed neighborhood. Each family picks a favorite color to move into.

Brown: The Abbotts. Pink: The Beavers

Green: The Craines. Gray: The Danubes

Cyan: The Edwards. Red: The Fishers

Blue: The Grammes. Yellow: The Higgins

The mayor wants their names displayed on the neighborhood map. The problem is - the mayor hasn't decided on which color gets painted on which house yet.

Notes

Introducing dict

How do we link the colors to each family? We don't know which house is going to get which color yet, i.e the house_colors parameter can change.

Python's dict can help you represent data that has key-value relationships.

1
2
3
4
5
6
family_colors = {'brown': 'Abbotts', 'pink': 'Beavers', 'green': 'Craines',
                 'gray' : 'Danubes', 'cyan': 'Edwards', 'red': 'Fishers',
                 'blue' : 'Grammes', 'yellow':'Higgins'}
another_dict = {} # <-- this is an empty dict
another_dict['some_key'] = 'some_value' # <-- adding data into this dict
another_dict[100] = 200 # <-- key and value can be anything
  • A dict is container of key-value pairs.
  • The keys in a dict are unique to each other.

Notes

Dict is key-addressable

For a dict D, you can access the value associated with the key K by doing D[K].

Dict key addressable

  • If the presented key doesn't exist in the dict, an exception will be thrown.

Notes

Dict is iterable

We can use a for loop on a dict.

1
2
for key in family_colors:
  print('%s = %s' % ( str(key), str(family_colors[key] )))

Dict for loop

Notes

Exercise: Printing names

Modify the house() function to accept a new parameter name. Print the name on the house.

Hint: use tom.write() to print on the canvas.

Notes

Answer:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
def house(size, color, name):
    tom.fillcolor(color)
    tom.begin_fill()
    tom.fd(size)
    tom.lt(120)
    tom.fd(size)
    tom.lt(120)
    tom.fd(size)
    tom.end_fill()
    tom.lt(30)
    tom.fd(size)
    tom.lt(90)
    tom.write(name)
    tom.fd(size)
    tom.lt(90)
    tom.fd(size)

Notes

Exercise: Neighborhood with names

Make the neighborhood() function take a new parameter families, a dict of color and family names. Then pass family names to the modified house() function.

Turtle neighborhood with names

Notes

Answer:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
def neighborhood(house_size, house_colors, families):
    for i in range(0, len(house_colors)):
        color = house_color[i]
        house(color=color, size=house_size, name=families[color])
        tom.rt(90)
tom.pu()
tom.bk(200)
tom.pd()
colors = ['brown', 'pink', 'green', 'gray', 'cyan', 'red', 'blue', 'yellow']   
family_colors = {'brown': 'Abbotts', 'pink': 'Beavers', 'green': 'Craines',
                'gray' : 'Danubes', 'cyan': 'Edwards', 'red': 'Fishers',
                'blue' : 'Grammes', 'yellow':'Higgins'}
neighborhood(house_size=50, house_colors=colors, families=family_colors)

Notes

A change of mind

The mayor changes his mind - he wants to reverse the order of the house colors:

No big deal, our code still works, and families get to keep their colors.

1
2
sroloc = ['yellow', 'blue', 'red', 'cyan', 'gray', 'green', 'pink', 'brown']
neighborhood(house_size=50, house_colors=sroloc, families=family_colors)

Notes

How it looks

Turtle neighborhood with names

Notes

Break

Notes

Notes