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?
Réponses
Trop de publicités?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
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)
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
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.
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.