Scoping out Functions

Jed Rembold

September 20, 2021

Announcements

  • I’m still working through the PS1 feedback!
  • Problem Set 2 is due tonight at midnight
  • Problem Set 3 will be posted tomorrow, and is the last PS before the first project!
  • No lab today! I’ll be in my office during those hours if you have questions!
  • Polling: rembold-class.ddns.net

Review Question

When the final line of the code to the right is run, what type of variable is x?

  1. integer
  2. float
  3. string
  4. None of the above
def func(A):
    m = str(A)
    n = m + m + m
    print(n)

y = 5.0
x = func(y)
print(type(x))

Parameter Purposes

  • Often functions need some sort of outside input in order to be useful
  • It is necessary for them to know enough details so that they can carry out the requested task, but not so many that the function becomes annoying to use
    • Imagine you were trying to accomplish the task yourself!
    • What is the minimum amount of information you would need to know?
  • The minimum necessary information needed for the function to accomplish its task is generally the information conveyed in the parameters
  • There is always a balance
    • More parameters makes your function more general, to be used elsewhere
    • More parameters are tedious and potentially error prone to enter if unnecessary

Jockeying for Position

  • So far we have used a positional way to assign arguments to parameters
    • First argument to first parameter, second to second parameter, etc
    >>> def func( first, second, third ):
            print( first, second, third )
    >>> func(1,2,3)
    1 2 3
    >>> func(2,6,4)
    2 6 4

The Word is Key

  • Arguments may also be specified by a keyword, in which the caller precedes the argument with a parameter name and equals sign
  • Always stores the argument value in the specified parameter
>>>  def func( first, second, third ):
        print( first, second, third )
>>>  func(third=4, first=2, second=6)
2 6 4
  • Keyword arguments can appear in any order
  • All keyword arguments must come after any positional arguments!

Default Slide Title

  • Python allows you to specify a default value for a parameter, which is will use if one is not directly supplied
  • Do so by adding an equals sign and a value after the parameter name
    • So you define default values when you define the function
    def introduction(name='Jed', age=36):
      print('My name is ', name, ' and I am ', age)
  • If providing any parameters after a default parameter, you must indicate them through keywords
>>> introduction()
My name is Jed and I am 36
>>> introduction('Bob', 25)
My name is Bob and I am 25
>>> introduction('Larry')
My name is Larry and I am 36
>>> introduction(age=68)
My name is Jed and I am 68

Returning Graphics

  • You can return any type of variable from a function, including GObject graphical objects
  • Can be useful to write simple functions that bundle together common tasks
  • For instance, to create a filled circle centered at some location:
def make_filled_circ(x_cent, y_cent, radius, color='black'):
    circle = GOval(
                  x_cent-radius, y_cent-radius, 
                  2*radius, 2*radius
                  )
    circle.set_color(color)
    circle.set_filled(True)
    return circle

Poll!

def Vegas(x):
    y = 2
    for i in range(5):
        x += y
    return x

x = 3
z = Vegas(x)
print('z =', z)
print('x =', x)

Consider the code to the left. When the final value of x is printed, what will its value be?

  1. 3
  2. 5
  3. 13
  4. None

Stacks and Scopes

  • Functions really do work as self-contained little boxes or environments!
    • “What happens in Vegas stays in Vegas
  • Whenever Python enters a new function, you can envision that it gets out a fresh new board to keep track of that function’s variables
    • What happens on that board does NOT affect whatever might have been defined or happened on other boards
    • Each board is commonly called a stack frame
  • When Python finishes with a function and returns, the board or stack frame for that function is thrown away!

Taking a Walk through Vegas

We’ll annotate the stack frames by hand as the earlier code runs:

def Vegas(x):
    y = 2
    for i in range(5):
        x += y
    return x

x = 3
z = Vegas(x)
print('z =', z)
print('x =', x)

Summary of a Function Call

  1. Evaluate the arguments in the context of the caller
  2. Reserve space for the function in a new stack frame
  3. Copy each positional argument to the corresponding parameter variable
  4. Copy each keyword argument to the parameter with that name
  5. For parameters with default values, if not already assigned, assign those values
  6. Evaluate statements in the function body, using current stack frame to look up values of local variables
  7. On encountering a return, compute the return value and substitute that value in place of the function call
  8. Remove the stack frame
  9. Return to the caller, continuing from just after the function call

Understanding Check

Riddle me this. What would be the printed value of z at the end of the code to the right?

  1. 27
  2. 25
  3. 19
  4. None of the above
def f(x,y):
    z = (x + 3) ** 2
    return y + z

x = 1
z = x + f(y=x,x=2)
print(z)

Name Resolution and Scope

  • When Python encounters a variable name in a program, it looks for where the variable was defined in an expanding search:
    1. Local - The local context is all the variables defined within the current function. This includes variables appearing as a parameter!
    2. Enclosing - The enclosing context consists of the names defined in a function enclosing the current one.
    3. Global - The global context consists of names defined outside of any function or imported into the current module.
    4. Built-in - The last place Python looks is in the names of any built-in functions, like abs, str, print, etc.
  • The part of a program in which a name is defined in called its scope

Scoping Example

def func1(x,y):
    return z + func2(x,y)

def func2(x,y):
    def func3(x):
        return (y + x) ** 2

    z = x - func3(y)
    return z - y


z = 1
print(func1(2,z))

Local Variables

  • In Python, assigning any value to a variable means that the variable is assumed to be local
    • This generally makes sense, as you would not want more specific functions overriding variables in other areas
  • Can lead to issues though:
def increment():
    x = x + 1

x = 0
increment()
  • There are a few ways to address this, but we’ll focus on one in particular when it comes to PGL
// reveal.js plugins