Dark theme

Control Flow II: Functions
[outline]


In this part we look at a final element of flow control within files: functions. Functions are chunks of code that can be called when we need them to do jobs. We can pass data into them, and get answers back. They're essentially a toolkit-like collection of code. As you might write functions for other people to use, we also start to look at documentation and ways of proving your code works as people expect it to.


First up, let's look at the basics of functions, how we get data into them and how we get data representing the answer or processing we wanted done, back out.

Functions (powerpoint)

Further info:

There's a great deal of confusion about the different ways of passing data into functions in the literature. The Python documentation calls the process of attaching a new label to something passed into a function "pass by assignment", which seems to be a reasonable way of discribing it. In other languages they talk about "pass by value", which usually means copying a value into the function so it is completely independent, and "pass by reference", which usually means passing the original object into the function. Neither of these two simple summaries is either complete or accurate, though. For example, in many languages people talk about the process going on in Python "pass by reference", as changing an complicated object in Python inside a function can result in it changing outside, but others may call it "pass by value" as the memory location of the object is being copied and used to make a new label. In general in Python if you think of it as labels being attached to the same thing, and the thing either having a mutable or immutable content, you can't go wrong.

For more detail on other ways to get stuff from functions, see the documentation.

For more on unpacking operators, see PEP 448.


Quiz: The correct version of the final line in this code is _____________________

def printit(text, ending, case):
    if (case == "UPPER"):
        print(text.upper(), end = ending)
    else:
        print(text.lower(), end = ending)

printit("hello world", ending="\n", "UPPER")

  1. printit("hello world", ending="\n", "UPPER")
  2. printit("hello world", end="\n", "UPPER")
  3. printit("hello world", ending="\n", case="UPPER")

Correct! This code would currently report positional argument follows keyword argument because ending is given as a kwarg, but not case. The interpreter at a first sweep is just looking at the number and type of variables, and as soon as you've abandoned positionality, everything is ambiguous if not given a keyword name; you might, for example, be trying to assign to the variable that here is taken by the kwarg (if the kwarg was being used for a later variable). Given this, the only solution above that works is the one that also makes case a kwarg argument.


Because functions are blocks: chunks of code that could be run at any stage within the execution of the code, they have their own internal and isolated set of variables that only act within the functions, that is, the "scope" of the variables is the function they're made within. We'll now look at this notion in detail, as it is an important source of complication and bugs.


Function scope (powerpoint)

Further info:

Scoping issues are often some of the most complicated bugs. If your code is acting very oddly, check out the issues in depth page for this part.

 


Quiz: What is needed to get the following code working is ________________________________________

def f1():
    b = a
    def f2():
        c = b
        print(c)
    f2()
a = "hello world"
f1()

  1. nothing.
  2. shifting the "hello world" line to the top.
  3. declaring b as global and c as nonlocal.

Correct! As long as a is set up before f1 is called, this will run fine. As none of the outer variables are reassigned, the variables stay ok within the inner blocks, and can be seen fine. This includes a because it is before it is used with the others in the sequence of execution. None of them are named the same either. You need to only worry about variables being set up before they are used, and reassigning variables with the same name.


Finally, as functions are often written for other people to use (that is, you quite often send people a file of functions to use), let's look at documentation – how you tell people what your code does; and testing – how you prove to both yourself and others that your code works as it should.


Further info:

The good Python style is set out in PEP 8.

You can find examples of the various doc systems and tests which we've put together on this page. All the info you need to run them is in the code as comments.

Documentation style details can be found in PEP 257.

For more information on pydoc documentation generation, see the Pydoc documentation.

There is a starter list of alternative documentation formating software on this Python wiki page.

A popular one is Sphinx, which comes with Anaconda. You can find out more in the tutorial and invocation guide.

For more information on doctests, see the doctest documentation.

For unit testing, see the Python unit testing library documentation. A list of assertion functions can be found here.

There's a good introduction on Wikipedia to Test Driven Development, and Continuous Integration.