Functions (Python)

This tutorial module demonstrates how to create a function in Python.

A function is a block of code that runs when called. In computational music research, functions may be used to define common tasks or operations that will be applied to different musical works or excerpts.

The keyword def is used to define a function. This code defines a function named “hello_function” that prints the phrase “Hello world!”:

def hello_function():
 print("Hello world!")

As with a for loop, the first line of the function ends with a colon. All subsequent lines of code within the function must be indented.

We call the function by entering its name (followed by parentheses):

hello_function()
> Hello world!

Functions are useful when we want to apply the same operation to multiple inputs. We specify an input to a function by including it within the parentheses. For example, if we want to be able to say “hello” to others, we might rewrite the function as follows:

def hello_function(a_name):
 print("Hello " + a_name)

(Note that within the quotation marks I’ve included a space after “Hello” so that the results will be legible as two separate words. The + operator concatenates strings without a space.)

When we call the function we need to specify a value for a_name so we know who to say “hello” to. Since we’re working with strings, we’ll use quotation marks around the name we choose:

hello_function("Dolly")
> Hello Dolly!

hello_function("Molly")
> Hello Molly!

It’s important to remember that any parameters we define inside the function are known as local variables, meaning that they cannot be used outside the function. If we try calling the variable a_name on its own, we get an error.

Functions are often used to perform mathematical operations on numeric data. This function transposes any note (given as a MIDI note number) up one octave:

def octave_transposer(note):
 note = note + 12
 print(note)

If we enter the note middle C (60), the output is the C an octave higher:

octave_transposer(60)
> 72

(Note that the + operator responds differently when we use numeric input, as compared with the string input in the previous example.)

We can use variables as inputs as well:

a = 53

octave_transposer(a)
> 65

We can even use functions inside of functions. For example, let’s say that instead of transposing a single note at a time, we want to be able to transpose a whole melody at once. We might use a for loop to iterate over each note of the melody, calling the octave_transposer function each time:

def melody_transposer(melody)
 for x in melody:
  print(octave_transposer(x))

This seems like it should work, but it isn’t quite perfect!

In fact, we have to make one minor adjustment to the octave_transposer function. We don’t want to print the output directly. Instead, we want to pass the output of the nested function (octave_transposer) to the enclosing function (melody_transposer).

So instead of using the print function, we’ll use a function called return:

def octave_transposer(note):
 note = note + 12
 return note

def melody_transposer(melody):
 for x in melody:
  print(octave_transposer(x))

Return sends the output of a function back to the point at which it was called. So now the output of octave_transposer will be seamlessly passed back into melody_transposer, where it can be printed.

Let’s try it with a short melody:

twinkle_twinkle = [60, 60, 67, 67, 69, 69, 67]

melody_transposer(twinkle_twinkle)

> 72
> 72
> 79
> 79
> 81
> 81
> 79

And sure enough, we have transposed the entire melody up one octave with a single function! Now we can use the same function on any melody whenever we need to.

For more, see the w3schools entry on functions in Python.