"""
 function_tricks.py

 This demonstrates several possibly confusing behaviors of functions,
 global variables, local variables, and return values in python.

 Jim M | Oct 2012 | MIT License
"""

# --- global string  ------------

global_foo = "This is a global"    # A global variable

def examine_global_foo():
    print "inside examine_global_foo : "
    print " global_foo = '" + global_foo + "' with id = " + str(id(global_foo))
    print

examine_global_foo()

def change_global_foo(x):
    global_foo = x
    print "inside change_global_foo : "
    print " global_foo = '" + global_foo + "' with id = " + str(id(global_foo))

print "global scope : global_foo = '" + global_foo + "' with id = " + str(id(global_foo))
print "calling change_global_foo"
change_global_foo("Something else")
print "global scope : global_foo = '" + global_foo + "' with id = " + str(id(global_foo))

print

# --- global list --------------

global_list = ['zeroth element', 'first element']

def change_global_list(x):
    print "inside change_global_list before change : "
    print " global_list = '" + str(global_list) + "' with id = " + str(id(global_list))
    global_list[0] = x
    print "inside change_global_list after change : "
    print " global_list = '" + str(global_list) + "' with id = " + str(id(global_list))

change_global_list("new value")
print "outside function, after change_global_list :"
print " global_list = '" + str(global_list) + "' with id = " + str(id(global_list))

# --- modifying lists ------------------

# Here are three similar attempts to modify
# a list of numbers within a function and
# have that modification available after the
# function finishes.
#
# Look carefully at what's going on.
#

ints = [5, 8, 10]
print "before: ints = ", ints

# 1:
def square_numbers_1(numbers):
    for number in numbers:           # fails; number is copy of numbers[i]
        number = number*number

square_numbers_1(ints)
print "1: ints = ", ints

# 2:
def square_numbers_2(numbers):
    for i in range(len(numbers)):    # OK; modifies list in place
        numbers[i] = numbers[i]**2

square_numbers_2(ints)
print "2: ints = ", ints

# 3:

def square_numbers_3(numbers):       # often best; returns new list
    new_list = []
    for number in numbers:
        new_list.append(number**2)
    return new_list

new_list = square_numbers_3(ints)
print "3: ints = ", new_list


# --- print vs return ------------------------------------

# Make sure you understand the difference between these two,
# both how they're defined and how they can be reasonably used.

def square(x):
    return x**2

def print_square(x):
    print x**2

a = 3            # define a number

# approach 1 : using a return value
print "The square of " + str(a) + " is " + str(square(a))

# approach 2 : putting the 'print' side effect within a function
print "The square of " + str(a) + " is",
print_square(a)

# Which of these four statements make sense?

print "Four function calls: "

square(a)

b = square(a)

print_square(a)

b = print_square(a)

syntax highlighted by Code2HTML, v. 0.93pm6