Variables locales en funciones anidadas

De acuerdo, tenedlo en cuenta, sé que se verá horriblemente enrevesado, pero por favor, ayúdame a entender lo que está sucediendo.

from functools import partial

class Cage(object):
    def __init__(self, animal):
        self.animal = animal

def gotimes(do_the_petting):
    do_the_petting()

def get_petters():
    for animal in ['cow', 'dog', 'cat']:
        cage = Cage(animal)

        def pet_function():
            print "Mary pets the " + cage.animal + "."

        yield (animal, partial(gotimes, pet_function))

funs = list(get_petters())

for name, f in funs:
    print name + ":", 
    f()

Da:

cow: Mary pets the cat.
dog: Mary pets the cat.
cat: Mary pets the cat.

Así que básicamente, ¿por qué no estoy recibiendo tres animales diferentes? No es elcage ¿'empaquetado' en el ámbito local de la función anidada? Si no, ¿cómo hace una llamada a la función anidada para buscar las variables locales?

Sé que encontrar este tipo de problemas por lo general significa que uno está "haciéndolo mal", pero me gustaría entender qué sucede.

Respuestas a la pregunta(3)

Su respuesta a la pregunta