Variáveis ​​locais em funções aninhadas

Ok, tenha paciência comigo, eu sei que vai parecer horrivelmente complicado, mas por favor me ajude a entender o que está acontecendo.

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()

Dá:

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

Então, basicamente, por que não estou conseguindo três animais diferentes? Não é ocage 'empacotado' no escopo local da função aninhada? Se não, como uma chamada para a função aninhada procura as variáveis ​​locais?

Eu sei que se deparar com esse tipo de problema geralmente significa que se está "fazendo errado", mas eu gostaria de entender o que acontece.

questionAnswers(3)

yourAnswerToTheQuestion