Functional Arguments & Scope

Jed Rembold & Fred Agbo

February 14, 2025

Announcements

  • Remember the due date for Project Wordle is Monday next week at 10 pm.
  • I’m still grading PS3, will be done by next week!
  • We will enter Ch6 of the text next week, which is a return to graphics
  • Remember the 1st midterm exam is next Friday Feb 23 at the usual class hall
    • I will provide more information about the exam on Monday next week
  • Today, we will deal with Ch5 (Function)
  • Polling continues https://www.polleverywhere.com/agbofred203

Review Question

Which of the below images would be produced by the following code?

gw = GWindow(200,200)
for c in range(0,10):
    for r in range(0,10):
        rect = GRect(20*c,20*r,20,20)
        if (r+c) % 2 != 0:
            rect.set_filled(True)
    gw.add(rect)
A
B
C
D

Function Review

  • A function is just a sequence of statements that have been collected together and given a name

    • Makes it possible to execute the statements multiple times much more easily
  • Some reminders about vocabulary:

    • Invoking or running a function by name is known as calling that function.
    • The caller passes information to a function using arguments.
    • When a function completes its block of code, it returns to its caller.
    • The function gives information back to the caller by returning a result
  • Syntax:

    def function_name( parameter_list ):
      function_body

Predicate Functions

  • Functions that return a Boolean value are called predicate functions

    def is_divisible_by(x, y):
      return x % y == 0
  • Once you have defined a predicate function, you can use it in any conditional expression!

    for i in range(1, 100):
      if is_divisible_by(i, 7):
          print(i)

Predicate No-nos

  • Don’t complicate your code for no reason!

  • Work directly with the boolean values when possible

  • Try not to code patterns like the following:

    def is_divisible_by(x, y):
      if x % y == 0:
          return True
      else:
          return False
    for i in range(1, 100):
      if is_divisible_by(i,7) == True:
          print(i)

Parameter Purposes

  • Functions perform some sort of service for their callers
  • It is necessary for them to know enough details so that they can carry out the requested task
    • Imagine you were trying to accomplish the task yourself!
    • What is the minimum amount of information you would need to know?
  • The necessary information needed for the function to generally accomplish its task is the information conveyed in the parameters

Jockeying for Position

  • So far we have used a positional way to assign arguments to parameters

    >>> def func( first, second, third ):
            print( first, second, third )
    >>> func(1,2,3)
    1 2 3
    >>> func(2,6,4)
    2 6 4
    • First argument to first parameter, second to second parameter, etc

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 Value

  • Python allows you to specify a default value for a parameter, which it 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=35):
      print(f'My name is {name} and I am {age}')
  • If providing any parameters after a default parameter, you must indicate them through keywords

Default Value

  • Different cases of calling the introduction function:

    >>> introduction()
    My name is Jed and I am 35
    >>> introduction('Bob', 25)
    My name is Bob and I am 25
    >>> introduction('Larry')
    My name is Larry and I am 35
    >>> introduction(age=68)
    My name is Jed and I am 68

Walk through vegas

  • Consider the code to below. When the final value of x and z are printed, what will their value be?
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)

Mystery word

  • Let us walk through this program and unravel what will be printed when the program complete execution.
def mystery (x):
    def enigma (s, t):
        t -= 2
      return s [::6] + s[t]
  y = len(x)
  z = x[1 - y]
  z += enigma (x, y)
  z += enigma (x, y - 2)
  print(z)

if __name__ == '__main__':
    print(mystery ("abcdefgh"))


Graphic function with default color

  • 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

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

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()
  • The variable x in the fuction is local within that scope, and another global x with value 0 can cause issues

// reveal.js plugins