Python for Designers

by Roberto Arista

Fork me on GitHub

How to Browse Sequences

abstract-11.svg

We already had a taste of what sequences are thanks to strings. But strings only include text. What if we need to store a bunch of numerical values? Or some strings together with numerical values?

Python provides two standard data types for containers where order matters: a mutable one, list(), and an immutable one, tuple(). They store an ordered sequence of value references. This means that if a list contains another list – of course this is possible – the inner one will not be copied inside the container, but a reference to it will be stored.

In Python a list is delimited by the characters [], while a tuple is delimited by characters ().

Here’s a list:

.py


    
list.svg

Now, this is a tuple:

.py


    
tuple.svg

As we said, elements in lists and tuples are of arbitrary nature: they can be any kind of object, None included. They can be empty too.

Emptiness usually does not make much sense for tuples, given they cannot be modified once created. Instead it is very common to initiate an empty list which will be populated during an iterative process triggered by a while or for construct. Consider the following example:

.py


    

The constructors list() and tuple() accept any kind of iterable as argument like strings or lists or tuples. They “listify” or “tuplefy” their arguments. For example, if a string is passed as argument to a list() function, the result will be a container where each character is stored separately:

.py


    

At this point, you might ask yourself: why both tuples and lists? Aren’t lists enough? Apart from the difference in terms of mutability, there is a semantic difference in the usage of tuples and lists.

While tuples are used to store heterogeneous data structures, lists are ordered sequences of the same stuff. Take note that they have the same degree of freedom concerning data types, it’s just a matter of semantics.

Let’s consider the following scenario: it’s time for a quick ride on our bike and we would like to track our journey using an application installed on a smartphone. Let’s assume this application is written in Python. Every few seconds the application will ask the smartphone hardware for:

  • gps coordinate x
  • gps coordinate y
  • date and time

.py


    

This data will be then organized in a tuple. Since the length of the container does not need to be flexible (e.g. we know we won’t add a z index to it) but just to record a state through multiple values, a tuple is a good choice.

The application’s goal is to track a route, which is a sequence of multiple position instances. So, the application needs a container which is flexible and can be extended until the end of the journey: a list.

.py


    

Once finished, the route of the journey is saved on the smartphone memory. A standard table would suit very well the purpose.

list-table.svg

Sequence Properties for Lists and Tuples

  • accessing
  • slicing
  • check containment
  • test equality
  • natural order
  • concatenation

List Methods

As we said, a list is a flexible container, which means that once created, it can be manipulated in multiple ways. Python provides a few specific methods for it

.append(item)

.py


    
append.svg

.extend(iterable)

.py


    
extend.svg

.insert(index, item)

.py


    
insert.svg

exercise 12.1

transform a right-angled triangle in a square adding a point

.remove(item)

.py


    
remove.svg

.pop(index)

.py


    
pop.svg

.index(item)

.py


    
index.svg

.sort()

.py


    
sort.svg

.reverse()

.py


    
reverse.svg

For Syntax

Python provides a for-loop syntax which is useful to iterate over a series of elements. Where while comes in handy when we need to keep doing something until a condition is matched, for is preferable when we need to browse a container. for can be used with any kind of iterable, which is a wider notion than sequences. Technically, an iterable can be non-sorted (as sets or dicts).

Here’s the general for construct:

.py


    

Note that the body is four spaces indented rightwards. for and in are protected keywords. eachElement is an identifier to which the body can refer to. Of course its name is arbitrary, it only needs to respect the standard rules for identifiers.

for.svg

The iterable can be created either before the for opening statement or created on the spot. Meaning that this example:

.py


    

is equivalent to:

.py


    

This also means that we could invoke a function which is able to generate an iterable on the spot

.py


    

Python provides a function that you will use very often in your coding routine: range(). This function returns an iterator –not a real list– which will provide a sequence of integers according to the following arguments

.py


    

start and step are optional. start has to be addressed if step is defined. Take into account that, as for the slicing notation, the stop value is not included into the range created.

This function will make the iteration over a sequence of integer number easy and compact:

.py


    

After the end of the loop the identifier will be still available in the program namespace, assigned to the last element of the iterable.

.py


    

How can this be useful in a graphic design application? Consider the following scenario: you would like to create a pdf document of sixteen pages and write on each page a sequential page number. DrawBot can do that of course:

16pages.svg

.py


    

A for construct is the perfect companion of an .append()list method. It is very common to create a series of values starting from a pre-existing one. Like making an all-caps version of a word sequence:

.py


    

Drawing Many Times in One Direction

Just like the while construct, for can be very helpful to draw shapes repetitively. In this way your code will look compact and it will be easy to edit.

Instead of:

4lines.png

.py


    

go for this kind of structure

4lines.png

.py


    

The advantages of the second version are enormous, starting for the very basic fact that you can add and subtract elements with almost no changes.

8lines.png

.py


    

What if you need to add points at the beginning and at the end? Easily done.

linesOvals.png

.py


    

Along with drawing, we can perform any kind of calculation. For example, the fill color of a shape could be defined by the identifier provided by the for construct. Here’s an example.

scaleGrey.png

.py


    

Or we can affect the arguments used to draw the shape itself:

lines.png

.py


    

Remember that if statements can be used in the for body, meaning that we can perform choices within an iterative process:

stripes.png

.py


    

Drawing Many Times in Two Directions

A single for construct allows repetition in one dimension. But, as we have seen with the previous example, other constructs can be used inside the for body. Which means that a second for loop can be nested into the first for loop. In this way the repetition becomes two dimensional.

If we need to draw a table or 90° based pattern, this technique becomes very handy. Consider the following drawing

matrix.svg

This is a bidimensional matrix, it is a simple table. Each element of the matrix is called cell. Each cell of this matrix can be described by two indexes: the index of the column and the row to which the cell belong. If we explicit write each index to each cell we obtain

matrix-number.svg

At this point we only need to define a size for the cell and we are able to draw the left column of the matrix

rows4.png

.py


    

or the bottom row the matrix

cols4.png

.py


    

If we combine the two constructs together we can draw the entire matrix calling the rect() function only once

rowscols4.png

.py


    

Matrix indexes can be drawn very easily

gridnumbers.png

.py


    

As for the single for construct, calculations performed within the body can affect the quality of the drawing. A one-dimensional gradient can easily become bi-dimensional

matrixRect.png

.py


    

and an if statement nested into the inner for loop can draw a chess board:

chess.png

.py


    

Please, note that nested for constructs can also be used to navigate nested data structures as a list of tuples:

listprinted.png

.py