menu COMPSCI 2120/9642/DIGIHUM 2220 1.0 documentation

CS 2120: Topic 3

Video for this week:

Yikes, what happened to your voice?

Sorry for my voice in videos 2 and 3 for this week.. I’ve caught a bit of a cold, and it happened to show up between recording parts 1 and 2.

Functions

_images/conjunction_junction.jpg
  • Say you want to be able to do a certain thing (i.e. find the area of a circle)

  • You may want to do it multiple times.. ideally you’d want a cleaner way to do this than to copy and paste it X times in your editor..

  • In Python, we can use a function:

    def my_function(parameter):
            result = parameter * 2
            print(result)
    
  • Once you’ve defined a function, you can call it exactly the same way you’d call a built-in function like print.

  • Let’s call our function:
    >>> my_function(2)
    4
    >>> my_function(7)
    14
    
  • When we call my_function, the Python interpreter executes the statements that make up the function, in order.

Function Parameters

  • Imagine an add_print(a,b) function that adds two numbers and prints the result. You want it to add any two numbers, not just two specific numbers. A function add_print(3,5) that can only add 3 to 5 wouldn’t be very useful. It would only ever print 8. So we introduce parameters.

  • Parameters are like variables. When you call the function, the parameter values get filled with whatever you set them to in the call.

  • Let’s create an add_print function:

    def add_print(a,b):
        print(a+b)
    
  • Now that the function is defined, we can call it. Like this:

    >>> add_print(5,2)
    7
    
  • The call add_print(5,2) gets handled like this:

    • The interpreter checks to see if it knows about a function named add_print

    • We just defined add_print, so it does.

    • When we defined it, we told the interpreter it should have two parameters: a and b.

    • The interpreter now takes the values in the call (in this case, 5 and 2) and assigns those values to the function parameters a and b.

    • In other words, the first thing the interpreter does in this case is set a = 5 and b = 2

    • Then the interpreter executes the body of the function, with the parameters having their new values.

Abstraction

What is abstraction?

Abstraction: reduce complexity by hiding unnecessary information

_images/push_for_coffee.jpeg

When you press a button to make coffee, you probably don’t care about what the machine is doing, and you don’t need to.

  • Why is abstraction important?

Try this…

Write down a sequence of instructions (i.e. a “program”) for boiling an egg. You can use the functions locate(pot), setup(egg_in_water_in_pot), and boil(egg).

Now try this…

Write down a sequence of instructions (i.e. a “program”) for boiling an egg. You cannot use any functions.

  • You’ve now written two programs at two levels of abstraction. Which was easier?

  • Functions allow us to add on layers of abstraction.
    • A low level function might worry about how to set the individual pixels of the display to show the letter A .

    • Would you want to cut-and-paste that code every time you needed to print A?

    • Instead, we have a function called print that hides all those messy details from us.

    • We call print, print calls other functions, which call other functions, which call other functions…

  • Without organizing things into levels of abstraction, writing complex software would be impossibly difficult.

A note on indentation

  • The general format for defining a function is:

    def function_name(p1,p2,p3,p4, ... ):
            statement 1
            statement 2
            ...
            statement m
    
  • statement 1, statement 2, ... , statement m make up the body of the function

  • You tell Python which statements make up the body of the function by using indentation (i.e. hitting the tab key).

  • without indenting, you will get a syntax error (more specifically an IndentationError)

  • make sure to be consistent in your indentation (whether you use a tab, 4 spaces, …).

Execution Flow

  • To make sense of programs, we need to know which instruction gets executed when

  • Execution begins at the first statement of the program. Statements are executed from top to bottom, one line at a time.

  • However, when the interpreter reaches a function, it processes the def statement only.. it does not go into the body of the function.
    • it “skips over” those lines and executes the first line outside of the function.

  • The statements in the body of the function are not executed until we call the function.

  • Let’s trace through this program:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    def dostuff(a,b):
            c = b*2
            d = (a+4)*2
            c = d + c
            return c
    
    x = 2
    y = 3
    print(dostuff(x,y))
    

Test yourself

In what order are these lines of code above processed by Python? (i.e. 1,2,3,5,9,etc.)

Function values

  • Notice how dostuff ended with a return statement.

  • The return statement tells Python: “return this value to whoever called this function”

  • With return, functions evaluate into values.

  • Consider:
    >>> print(dostuff(2,2))
    16
    >>> print(dostuff(4,4))
    24
    >>> print(dostuff(2,2) + dostuff(4,4))
    40
    
  • When the interpreter hits a dostuff function call, it executes the function, which results in a returned value.

  • So, when execution flow comes back to the calling program, the call to dostuff gets replaced with whatever value got return ed.

Composition

  • Python functions can be composed just like mathematical functions.

  • We’ve already seen print composed with dostuff

  • We can nest functions, too:
    >>> dostuff(dostuff(2,2),dostuff(2,2))
    72
    
  • If you get confused tracing nested functions, try the following:
    • Find a function call you can evaluate. Evaluate it.

    • Replace the function call with the value it returns

    • Keep doing this until you’re down to one value.

Variable scope

  • If you set a variable inside a function, it is local to that function.

  • No other function can see a function’s local variables. They are local. Consider this code:

    def domore(a,b):
        c = 2*a + b
        return c
    
  • What happens if I do this::
    >>> print(domore(4,4))
    12
    >>> print(c)
    NameError: name 'c' is not defined
    
  • Error! But c is defined in domore! Why did we get an error?

  • Variables have scope. We will come back to this later in the course.

Optional parameters for functions

  • Sometimes you want a function to have an optional parameter, with a pre-specified default value.

  • This is done very easily:

    def my_function(a,b,c=3):
       do_stuff()
    
  • When you call my_function(5,12), a will have value 5, b value 12 and c value 3.

  • Because we specified a default value for c, we don’t have to provide one when we call the function.

  • If we want to override the default though, we can: my_function(4,3,2) .

Import

  • Sometimes you want to make a big library of functions. Maybe they’re related to analysis data from your research.

  • You’d like to access some of those functions from another program that you’re writing.

  • If you put your functions in a file called ‘myfuncs.py’, you can import them into another program like this:
    >>> from myfuncs import *
    
  • (The * here means “everything)

  • You could also use:
    >>> import myfuncs
    
  • BUT, after importing in this way, to access a function called dostuff in the file myfunc you’d have to type:
    >>> myfuncs.dostuff(...)
    

For next class