127 votes

nonlocal mot-clé en Python 2.x

Je suis en train de mettre en œuvre une fermeture en Python 2.6 et j'ai besoin d'accéder à une variable non locale, mais il semble que ce mot-clé n'est pas disponible en python 2.x. Comment doit-on l'accès non des variables dans les fermetures, dans ces versions de python?

132voto

Chris B. Points 14211

Python peut lire nonlocal variables en 2.x, tout simplement pas de changement . C'est gênant, mais vous pouvez travailler autour d'elle. Il suffit de déclarer un dictionnaire, et de stocker vos variables comme des éléments qu'il contient.

Pour utiliser l'exemple de Wikipedia:

def outer():
    d = {'y' : 0}
    def inner():
        d['y'] += 1
        return d['y']
    return inner

f = outer()
print(f(), f(), f()) #prints 1 2 3

39voto

Marc van Leeuwen Points 803

La solution suivante est inspiré par la réponse par mikez302, mais contrairement à cette réponse ne traiter plusieurs appels de l'extérieur de la fonction correctement. La "variable" inner.y local à l'appel en cours d' outer. Seulement ce n'est pas une variable, puisque ce qui est interdit, mais un attribut de l'objet (l'objet à la fonction inner lui-même). C'est très laid (notez que l'attribut ne peut être créée qu'après l' inner fonction est définie), mais semble efficace.

def outer():
    def inner():
        inner.y += 1
        return inner.y
    inner.y = 0
    return inner

f = outer()
g = outer()
print(f(), f(), g(), f(), g()) #prints (1, 2, 1, 3, 2)

14voto

ig0774 Points 10389

Je pense que la clé ici est ce que vous entendez par "accès". Il devrait y avoir aucun problème avec la lecture d'une variable en dehors de la fermeture de la portée, par exemple,

x = 3
def outer():
    def inner():
        print x
    inner()
outer()

devrait fonctionner comme prévu (impression 3). Toutefois, en substituant la valeur de x ne fonctionne pas, par exemple,

x = 3
def outer():
    def inner():
        x = 5
    inner()
outer()
print x

s'imprime toujours 3. De ma compréhension de la PEP-3104 c'est ce que le non mot-clé est censé couvrir. Comme mentionné dans le PEP, vous pouvez utiliser une classe pour accomplir la même chose (genre bordélique):

class Namespace(object): pass
ns = Namespace()
ns.x = 3
def outer():
    def inner():
        ns.x = 5
    inner()
outer()
print ns.x

12voto

Elias Zamaria Points 13196

Il est une autre façon de mettre en œuvre locale des variables en Python 2, dans le cas où aucune des réponses ici ne sont pas souhaitables pour quelque raison que ce soit:

def outer():
    outer.y = 0
    def inner():
        outer.y += 1
        return outer.y
    return inner

f = outer()
print(f(), f(), f()) #prints 1 2 3

Il est superflu d'utiliser le nom de la fonction dans l'instruction d'affectation de la variable, mais il semble plus simple et plus propre pour moi que de mettre la variable dans un dictionnaire. La valeur est souvenu d'un appel à l'autre, tout comme Chris B. réponse.

3voto

Marcin Points 25366

Il y a une verrue en python les règles de portée de cession rend une variable locale à son immédiatement joignant la portée de la fonction. Pour une variable globale, vous permettrait de résoudre ce avec l' global mot-clé.

La solution est d'introduire un objet qui est partagée entre les deux étendues, qui contient des variables mutables, mais est lui-même référencé par une variable qui n'est pas affecté.

def outer(v):
    def inner(container = [v]):
        container[0] += 1
        return container[0]
    return inner

Une alternative est de certaines étendues hackery:

def outer(v):
    def inner(varname = 'v', scope = locals()):
        scope[varname] += 1
        return scope[varname]
    return inner

Vous pourriez être en mesure de découvrir quelques astuces pour obtenir le nom du paramètre outer, puis de le passer comme varname, mais sans compter sur le nom de l' outer vous aimeriez avoir besoin d'utiliser un Y combinator.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X