Functions & Scope

Dr Andy Evans

[Fullscreen]

  • Scope is the space within which a variable label exists and can be used. Python talks of names being bound to the code in an area and that determining its scope. Binding in Python is usually through assignment.
  • So far, we haven't had to deal with it. Loops/if compound statements don't effect it:
    a = [1] # "a" can be declared here
    for i in 1,2,3,4:
        a = [1] # or here.
        a[0] = i
        print (a) # 1 ,2 ,3 ,4
    print (a) # 4
    print (i)
  • All the "a" here are treated as same object wherever they are first used, and "i" can be seen everywhere after it has been first declared.
  • Functions have more complicated scoping. Although the declaration of a function looks similar to a compound statement clause header, the function declaration generates a block, which has scoping rules.
  • Starting with variables labels made inside a function:
    def a ():
        b = 10
        print(b)
    a()
    print(b)
  • This will run the print statement within the function, but fail for that outside because b has been first allocated inside the function.
  • This makes b a local variable, only available within the function and functions within it.

Function scope

  • One solution in a script is to define the variable outside the function:
    b = 10
    def a ():
        print(b)
    a()
    print(b)

Function scope

  • One solution in a script is to define the variable outside the function:
    b = 10
    # b here is a "global variable"
    # it can be see everywhere there
    # isn't a variable of the same
    # name assigned.

    def a ():
        print(b)
        # b here is a "free variable" i.e.
        # defined outside the current block. a()
    print(b)
  • As soon as you declare a variable inside a block, it is a new variable label. Contrast:
    b = 10
    def a ():
        b = 20
        print(b) # Prints 20.
    print(b) # Prints 10.
    a()
    print(b) # Prints 10.
    with:
    b = 10
    def a ():
        print(b) # Prints 10;
    print(b) # Prints 10.
    a()
    print(b) # Prints 10.
  • Variables outside of functions in scripts are global: in theory they can be seen anywhere. However, the rule about local assignments creating local variables undermines this.
  • To force a local assignment to a global variable, use the global keyword, thus:
    b = 10
    def a ():
        global b
        b = 20
        print(b) # Prints 20.
    print(b) # Prints 10.
    a()
    print(b)
    # Now prints 20 as the function
    # changes the global b.

Nested scopes

  • With nested functions you can imagine situations where you don't want to use a global, but do want a variable across all the functions:
    a = 1
    def f1():
        a = 2
        def f2():
            a = 3
            print(a)
    # Prints 3.
        f2()
        print (a) # Prints 2 - but we'd like 3.
    f1()
    print(a) # Prints 1.

Nested scopes

  • We can achieve this with the nonlocal keyword, which propagates variable labels out one nest (unless there they are set to global).
    a = 1
    def f1():
        a = 2
        def f2():
            nonlocal a
            a = 3
            print(a)
    # Prints 3.
        f2()
        print (a) # Prints 2 - but we'd like 3.
    f1()
    print(a) # Prints 1.

Variable labels

  • Note that variable labels in function declarations are also local to the function, but we're only talking about labels here, not values:
    def a(b):
        print(b)

    c = "hi you"
    a(c)
  • Here, b is local to the function, but the "hi you" referred to can be seen anywhere there's a label attached to it.
Two labels attached to a variables