Recitation 4: Exam Review

Scope

You should be comfortable with Python scope. Learn the LEGB rule well.

Some of you may have been wondering what the E stands for, considering the L is already delimited by the local function definition.

For now, we won’t quiz you on the E. For that, we’ll need to talk about functions within functions and strange things like Objects and Classes. Ignore it for now.

Given a code example like this, you should be comfortable in explaining why it fails.

def meaning_of_life():
    meaning = 42

print meaning

That’s an obvious one. How about a more challenging one involving global variables?

life = 42

def hitchHikersGuide():
    print life
    life = 0

hitchHikersGuide()
print life

This is a tricky one, and it requires you to be very comfortable with how Python evaluates local and global values. Let’s start simple. Will the code run without an error?

No, it won’t. In fact, here is the error it will throw.

UnboundLocalError: local variable 'meaning' referenced before assignment

An UnboundLocalError. Interesting – probably something many of you haven’t seen except once on the lab before running to the help of a section leader. It means you’re trying to access a local variable before defining it. Here’s another example of the UnbounbLocalError:

def hey():
    print dude
    dude = 7

Python sees that dude is defined, it’s just defined after you’re trying to use it in the print statement. Same thing is happening with meaning. But wait a minute! Isn’t meaning a global variable?

No, it’s not. The problem here is we’ve defined a local variable and a global variable with the same name! Python sees that within the function hitchHikersGuide, we’re actually defining a variable called life. So it assumes when we try and print it, we mean the local one.

Note that it doesn’t try and access the local one, and upon failing, try and see if it works with the global one. Computers aren’t that smart. It tries to get the local variable, fails, and then cries.

Fundamentally, naming a local and global variable with the same name means that within the local variable’s scope, you cannot access the global variable! This is referred to as “stomping” on the global variable.

How about that confusing word global. Be familiar with it. You should know how to use it and when it’s needed. Since you had an entire lab on this point, I won’t make another exercise involving it here.

Loops

You should be very proficient with loops. While loops and for loops – the differences, and their limitations.

While Loops

How many times does the following code print output?

i = 0
while i <= 10:
    print "Hello!"
    i += 1

Eleven. Computer scientists start counting from zero. Okay, that was fairly easy. What about this one? (Same question.)

i = 0
while i <= 10:
    j = 0
    while j <= 10:
        print "Hey!"
        j += 1
    i += 1

Top loop executes eleven times, and for every time the top loop executes, the inner loop executes eleven times. Simple enough: 11 x 11 = 121.

For Loops

You should be familiar with the various types of for loop headers and why we use each type. In addition, you should be reasonably familiar with lists and the common operations associated with them.

What is the output? What does the following code do to each of the lists?

joke = ["Do", "you", "like", "impressions?"]
response = ["Yeah!"]
punch = ["Why?", "Pause", "That", "was", "Socrates"]

for word in joke + response + punch:
    print word
    word = "Not funny"

The output is simple enough. It prints every word contained in the three lists, one word per line. As for the second question, the answer is nothing. It does nothing to the lists. If you’re not clear why, look up the for loop lecture.

What’s the point of this code?

youCantGuess = []
words = ["dude", "avacado", "dudett", "broccoli", "not a food", "totally food"]
for i in range(len(words)):
    if i % 2 == 0:
        youCantGuess.append(words[i])

It adds all the even-indexed elements in words to the list youCantGuess.

Great! What about splice notation?

crazyList = [2, 3, 5, 7, 11, 13, 17, 19, 23]
notSoCrazy = [1, 4, 6, 8, 9, 10, 12, 14, 15]
for i in (crazyList[::-1] + notSoCrazy)[:6:-2]:
    print i

Woah. Some pretty intentionally obfuscatory code, eh? Let’s step through this, slowly.

You’ve seen the classic [::-1] before – nothing new there. It reverses a list. So we add the reversed crazyList to the regular notSoCrazy. That result isn’t so bad:

[23, 19, 17, 13, 11, 7, 5, 3, 2, 1, 4, 6, 8, 9, 10, 12, 14, 15]

Okay. What does the next part do? There’s no starting position – so that means it defaults to one of the two ends of the list. The ending position is 6, which means that the element at index 6 is the first element that won’t be included. Lastly, the step is -2, which means we’re going to start at the right end of the list and go left until we hit the element with index 6. However, since the step is -2, we’ll ignore every other element.

0    1   2   3   4   5   6   7   8  9 10 11 12  13  14  15  16
[23, 19, 17, 13, 11, 7, 5, 3, 2, 1, 4, 6, 8, 9, 10, 12, 14, 15]

On the top we see the indices, and on the bottom we see the actual list. So let’s take the elements, starting from the right end, and going until (but not including!) index 6, ignoring every other one.

So we take 15, ignore 14. Take 12, ignore 10. You see how this goes. Here’s the final result!

[15, 12, 9, 6, 1, 3]

Of course, we don’t expect you to look at this for ten seconds and solve it. But we do expect that, given a pencil and a piece of paper, you could work through this over the course of several minutes. Annoying? Perhaps. But it shows a very thorough understanding of the material.

Debugging

You should be comfortable stepping through the code. We’ll give you a snippet of code, and if it runs you should explain what the output is. If you think it won’t run, you should explain what you think the error will be.

Want practice? Why not.

Exercise 0:

stuff = [5] * 3
print stuff

Answer:

[5, 5, 5]

Wow! Pretty cool way to create a quick list, huh? How about another one.

Exercise 1:

def nyanCat():
    global meow, woof
    print "meow!"
    while meow > woof:
        print "meow!"

def doge()
    global meow, woof
    print "woof!"
    while woof > meow:
        print "woof!"

meow, woof = 3, 4
nyanCat()
doge()

This one is slightly tricky, because it has output, but it also has a major bug. Here is the output.

meow!

However, there is also an infinite loop! meow and woof are never decremented, so doge function goes on forever!

Exercise 2:

for char in 'Oh my god!':
    print char

Answer:

You can iterate through strings one character at a time.

O
h

m
y

g
o
d
!