20130131
This week we looked at several topics:
Global and Local Variables
Dictionaries
Recursion
Global and Local Variables
A
Global Variable is a variable that is assigned a value in the main
program. A Local Variable is a variable that is assigned a value
inside a function - this includes any parameters that the function
might have. Local variables can only be used and referred to
inside the function where they are defined.
Global and local variables can have the same name. Consider this code:
def fun_1():
x = 3
print "in fun_1 x = ",x
fun_2()
print "back in fun_1 x = ",x
def fun_2():
print "in fun_2 x = ",x
x = 4
fun_1()
print "in main program, x = ",x
In
this example there is a global variable called x, and this x is
assigned the value 4. Then fun_1 is called - fun_1 creates a
local variable called x and assigns it the value 3. Then fun_1
calls fun_2 ... which prints x. At this point, the currently
executing function (fun_2) does not have a local variable called x,
because it does not assign x a value. So in fun_2, the reference
to x is to the global variable x, and the value printed is 4
When
fun_2 returns to fun_1, x refers to the local variable which has the
value 3. Finally fun_1 returns to the mail program, where x
refers to the global variable
Notice that fun_2 would cause an
error message if we used it in a program where there was no global
variable called x. This is highly undesirable - we want functions
to be self-contained and fully functional as long as they are provided
with appropriate parameter values. For this reason, a general
rule of good program design is to avoid writing functions that refer to
global variables.
However, there are exceptions. For
example, we might be writing a program that interacts repeatedly with
the user, and addresses her by name. We could pass the user's
name as a parameter to every one of the functions, or we could make
user_name a global variable and refer to it in each function.
def well():
print user_name+", you are doing well"
def try():
print user_name+," you should try harder"
def meet():
print "I am glad to meet you, "+user_name
# main program
user_name = raw_input("Please enter your name ")
meet()
In
general, even when we can justify writing functions that refer to
global variables, it is considered bad practice to write functions that
attempt to change the value of a global variable. This is why
Python automatically creates a local variable whenever a function
contains an assignment statement (as in the example above when fun_1
assigns a value to x). However, even this rule can be broken.
If it ABSOLUTELY necessary to give a function the ability to
change a global variable, the function must contain the line "global
<variable name>". For example
def fun_3():
global x
print x
x = 10
print x
# main program
x = 5
print x
fun_3()
print x
In fun_3, all references to x, including the line "x = 10", refer to the global variable called x.
The
bottom line is, unless there is an extremely good reason otherwise,
functions should not make any reference to global variables.
Dictionaries
A dictionary is a collection of pairs of data objects. In each pair, the first element is called the key and the second element is called the value.
Basically, we can treat a Python dictionary as a look-up table.
When we add a pair to the dictionary, we can use the key to retrieve the value.
For example
my_dict = {
"Popeye" : "sailorman",
"Clark Kent" : "reporter",
"Peter Parker" : "journalist",
"Bugs Bunny" : "sadist"
}
creates a dictionary containing four pairs. In each pair, the character's name is the key and their profession is the value.
We
can access the values stored in the dictionary using syntax that looks
a lot like the syntax for accessing a list: for example
job = my_dict["Clark Kent"]
for k in my_dict:
print k , my_dict[k]
We can add new pairs to the dictionary:
my_dict["Bruce Wayne"] = "millionaire playboy"
or change existing values
my_dict["Bugs Bunny"] = "psychopath"
We can create an empty dictionary in two different ways:
dict1 = {}
dict2 = dict()
The
keys in a dictionary do not have to all be of the same type - they can
be numbers, string, or some of each (in fact they can be any
non-mutable object, which basically just rules out lists and some other
things we haven't seen yet). The values can also be of mixed
types, and can be any type of object at all.
In your lab you will use a dictionary in which the values are
embedded dictionaries. As an all-in-one example, consider this
crazy_dict = {}
crazy_dict["William"]
= "The conqueror"
# string key,
string value
crazy_dict[42] = "the answer"
# number key, string value
crazy_dict[10]
= 2.544
# number key, number value
crazy_dict["alpha"]
= [1,2,"Cheerios",8]
# string
key, list value
crazy_dict[-99] = { 7 : "seas" , "agent" : 86}
# number
key, dictionary value
Of course in practice the keys are
usually all of the same type (all numbers, all strings, etc) and the
values are also all of the same type (though often of a different type
than the keys).
If you print a dictionary (as in the code
fragment above) you will see that the keys and values are not stored in
any predictable order - not ascending order (so why call it a
dictionary?) and not in the order in which they are added. The
order is not random - but it is the result of the way the dictionary is
stored in memory. It is a bad idea to think of a dictionary as a
type of list in which the indices are keys that we choose, rather than
integers 0, 1, 2 ... Lists are inherently positional structures, whereas dictionaries are associative structures. We can't take a slice of a dictionary.
We can delete pairs from a dictionary using the del command
del crazy_dict[42]
will delete the pair that has 42 as its key.
We get an error if we try to access a dictionary using a non-existent key. Fortunately we can test for this using in
if x in some_dict:
y = some_dict[x]
else:
y = 0
and not in
if x not in some_dict:
y = enterbox("Enter the value to store with " + str(x))
some_dict[x] = y
else:
msgbox(str(x) + " is already in the dictionary")
We can retrieve a list containing all the keys in a dictionary with the keys method:
list_of_keys = crazy_dict.keys()
We can also access the key, value pairs in a dictionary using the iteritems method:
for k, v in crazy_dict.iteritems():
print k, v
Dictionaries versus Lists
Use a list when
- the order of the information matters (for example, the list contains jobs we are to do, in sequence)
- the position of an item matters (for example, we may want the "middle" value)
Use a dictionary when
- the data items have a natural index field (such as the names of
the characters stored in my_dict above)
- the natural index values do not form a consecutive sequence (like 0, 1, 2, ...)
- the order of the stored information is unimportant