Code Toolkit: Python, Spring 2026

Week 8 — Wednesday, March 11 — Class notes

  1. Review: lists
  2. Background & overview: Timing and state
    1. History and inspiration
  3. Timing: a numeric timeline with millis()
  4. State: a new way to use variables
  5. Functions: project planning, reusability and modularity
  6. Wrapping up and homework

I. Review: lists

Last week we talked about lists, an example of a data structure.

To review that, we looked at Ava's homework (in Google Drive here).

The first thing I did was remove some extra append() commands, which were causing the x and y lists to be of different lengths. This would probably be considered a bug, although it did not create any noticeable problems in the way this code was running.

But we realized that by removing those, it removed an effect that Ava was going for in which the circles she is drawing were intended to be spread out at different vertical locations. My solution was to import the choice() command from the Python library random. (Please note: I have included this here in these notes in slightly different way than I did in class. I think the method here is more clear because it only imports choice(), which means we do not have to change all the places that Ava using already using the Processing random() command.)

In the below code, both lists will always be of the same length:

from random import choice
y =[]
x = []
number_of_things = 100
def setup():
    size(500, 500)
    rectMode(CENTER)
    
    i = 0 
    while i < number_of_things:
        x.append(i*10)
        y.append(250)
        y.append(100)
        y.append(400)
        y.append( choice([250,100,400]) )
        i = i + 1

def draw():
    background(255,255,255, 10)

    i = 0
    while i < number_of_things:
        circle(x[i], y[i], random(10,50))
        fill(i*100, random(0,i*20) , 150)
        if dist(mouseX, mouseY, x[i], y[i]) > 10:
            x[i] = x[i] + random(-5,5)
            y[i] = y[i] + random(-5,5)
        
        i = i + 1

Ava's primary question was how to do part two of last week's homework.

To achieve that, I removed the loop with the append() commands inside def setup() and set number_of_things to zero. The effect of this will be that when the program starts running, there will be no circles drawn to the screen. That looks like this:

from random import choice

y =[]
x = []
number_of_things = 0
def setup():
    size(500, 500)
    rectMode(CENTER)
    
    i = 0
    while i < number_of_things:
        x.append(i*10)
        y.append( random.choice([250,100,400]) )
        i = i + 1

def draw():
    background(255,255,255, 10)

    i = 0
    while i < number_of_things:
        circle(x[i], y[i], random(10,50))
        fill(i*100, random(0,i*20) , 150)
        if dist(mouseX, mouseY, x[i], y[i]) > 10:
            x[i] = x[i] + random(-5,5)
            y[i] = y[i] + random(-5,5)
        
        i = i + 1

To finish part two of the homework, we want to make sure that whenever the user presses the mouse, a new circle is created. To achieve that, add the following block at the bottom of the code:

def mousePressed():
    global number_of_things
    x.append(number_of_things*10)
    y.append( choice([250,100,400]) )
    number_of_things = number_of_things + 1

Now, whenenver the user clicks the mouse, we will append one value to x and one value to y, and also increment the number_of_things variable, which will effect how many times the while loop runs.

I also talked about the len() command (introduced last week), which returns the length of a list. Using this, we can actually get rid of the number_of_things variable entirely:

from random import choice

y =[]
x = []
number_of_things = 0
def setup():
    size(500, 500)
    rectMode(CENTER)
    
def draw():
    background(255,255,255, 10)

    i = 0
    while i < len(x):
        circle(x[i], y[i], random(10,50))
        fill(i*100, random(0,i*20) , 150)
        if dist(mouseX, mouseY, x[i], y[i]) > 10:
            x[i] = x[i] + random(-5,5)
            y[i] = y[i] + random(-5,5)
        
        i = i + 1

def mousePressed():
    global number_of_things
    x.append(len(x)*10)
    y.append( choice([250,100,400]) )
    number_of_things = number_of_things + 1

Next I showed how you could add some additional properties to the circles — in this case, a size and color. Here, the size and color of each circle will still be randomly generated, like Ava originally did, but they will be fixed for each circle, with random() called when the circle is being created rather than every frame. This will create a less frenetic effect, which may or may not be what you are going for!

from random import choice

y =[]
x = []
sz = []
c = []

def setup():
    size(500, 500)
    rectMode(CENTER)

def draw():
    background(255,255,255, 10)

    i = 0
    while i < len(x):
        circle(x[i], y[i], sz[i])
        fill(c[i])
        if dist(mouseX, mouseY, x[i], y[i]) > 10:
            x[i] = x[i] + random(-5,5)
            y[i] = y[i] + random(-5,5)
        
        i = i + 1

def mousePressed():
    x.append( len(x)*10 )
    y.append( choice([250,100,400]) )
    sz.append( random(10,50) )
    c.append( color(len(x)*100, random(0,len(x)*20) , 150) )

Finally, Maya asked a great question: Is there a way we could do this without having to manage four separate lists? Can we think of these circles (or "creatures") more as objects?

This is a great question and the answer is yes! Object-oriented programming is an approach to how to think about code that uses concepts like classes and objects to model data and algorithms. (I have another comment about this below.) True object-oriented programming requires some new syntax that we will not be covering this semester. But we can simulate an object-oriented approach to this example.

The below code creates just one big array to hold all the circles which I call creatures. Then, every time we are creating a new "creature", we make a small array of 4 items, and add that array to the creatures list. So we have a list of lists ...

from random import choice

creatures = []

def setup():
    size(500, 500)
    rectMode(CENTER)

def draw():
    background(255,255,255, 10)

    i = 0
    while i < len(x):
        c = creatures[i]
        circle(c[0], c[1], c[2])
        fill(c[3])
        if dist(mouseX, mouseY, c[0], c[1]) > 10:
            c[0] = c[0] + random(-5,5)
            c[1] = c[1] + random(-5,5)
        
        i = i + 1

def mousePressed():
    c = [ len(x)*10,
         choice([250,100,400]),
         random(10,50),
         color(len(x)*100, random(0,len(x)*20) , 150) ]
    creatures.append(c)
(jump back up to table of contents)

II. Background & overview: Timing and state

We've already seen how to draw shapes and make them move on their own. This motion would typically start when the program started running and continue forever. Or maybe it would be triggered or changed by user interaction in some way. Today we are going to talk about timing: how to create motion that is in some way scheduled, chorreographed, triggered with some delay, or that repeats at some interval.

The term time-based media is often used to describe work in primarily in sound and the moving image, although digital media like video games and motion graphics are also included. Today we will see some coding techniques to implement time-based behavior in interactive computer programs of the sort we've been working on. The goal of today will be to think about how to work with the domain of time in ways that are analagous to how we have so far been working within the domain of space.

a. History and inspiration

Oskar Fischinger

One incredible example of early time-based media is the work of Oskar Fischinger. Fischinger was an artist in the first part of the 20th century and a pioneer in animation and motion graphics. A classic example of his work is the animated film Studie nr 8, 1931.

You might be inclined to think that historically, animation must have preceded cinema, but in fact there is a case to be made for understanding these in the opposite order. Several modern artists and illustrators in the early 20th century were inspired by cinema to create animation, and used the principle of cinema — a continuous strip of film, divided into cells of static imagery that flicker by the viewer's eyes — to create early animation and motion graphics. In fact, many of these innovators actually worked on film strips, drawing and etching into the cells by hand. See for example Jonathan Crary's Techniques of the Observer or Gregory Zinman's Making Images Move for deeper discussion of this history.

Fischinger actually contributed to Disney's Fantasia but quit uncredited because of creative differences. In 2012, the Whitney museum showed an exhibition of his artwork called "Space Light Art". There is great documentation for this show online and I highly recommend taking a look!

III. Timing: A numeric timeline with millis()

(jump back up to table of contents)

IV. State: a new way to use variables

So far we have been using variables primarily for numeric things (like shape sizes, positions, or colors), and also for Boolean True/False values.

Today we saw how we could also use variables to keep track of time represented as a number — so another example of using variable for something numeric.

But what if we want the program to change over time in a way that is not explicitly tied to timing. For example, what if we wanted the program to be able to switch back and forth between two or more very different actions or operations, or if we want the program to operate in different phases or modes, maybe cycling or toggling between those in response to user input or something else?

In computer science, the term for keeping track of the status of the program is state. We might ask, what state or phase is the program in? This could be used to implement the levels of a video game for example.

The way to do this is by using variables. This is not very different from anything that we have been doing so far. I just want to show a few examples that emphasize how you can use variables in some slightly different ways — ways that are not strictly numeric in the ways we have been using them, but also that keep track of state in way that enables more options than simply True / False values.

Example: A light switch

(jump back up to table of contents)

V. Functions: project planning, reusability and modularity

Functions are a way to organize your code.

Now that you've started thinking about the midterm project, you will be working on a computer program that is a little bit longer and a little bit more complicated. You need a way to keep this organized and manageable. Functions give you a technique for how to do that.

(Another strategy for code organization involves a technique called object-oriented programming, which uses things called classes and objects. We might talk about this later in the semester if there is time and interest.)

A function takes any sequence of commands, groups them together into a block, and gives that block a name. Then, just by using that name, you can automatically run all those commands.

Keep this in mind as you work on the midterm!

(jump back up to table of contents)

VI. Wrapping up and homework

The homework for this week builds on all of the above.