Dans l'extrait non-travail , vous affectez à a
lorsque vous dites "a -= 1
". Pour cette raison, à l'intérieur de function2
, a
est local à cette portée, pas pris la portée englobante. Les fermetures de Python sont lexicales - elles ne recherchent pas dynamiquement le a
dans le cadre de function2
et s'il n'a pas été assigné, allez le chercher dans le cadre de function1
. Notez que cela ne dépend pas de la récursivité ou de l'utilisation des fermetures du tout. Prenons l'exemple de cette fonction
def foo():
print a
a = 4
L'appeler vous obtiendrez un UnboundLocalError
aussi. (Sans a = 4
, il utilisera soit le a
global, soit, s'il n'y en a pas, NameError
.) Étant donné que a
est potentiellement affecté dans cette portée, il est local.
Si je concevais cette fonction, je pourrais utiliser une approche plus comme
def function1():
a = 10
def function2(a=a):
print a
a -= 1
if a > 0:
function2(a)
function2()
(ou bien sûr for a in xrange(10, -1, -1): print a
;-))
En effet, c'est le point clé dans la conception de cette fonction vous ne pouvez pas attribuer aux champs non locaux. (Note: 'al' est * mutable *, c'est pourquoi cela fonctionne.) –
Je pense qu'il est important, par souci de clarté, de faire la distinction entre al la variable et les valeurs que contient al. Cela revient toujours à des pointeurs pour moi alors laissez-moi vous dire ceci; Vous ne pouvez pas faire référence à une nouvelle liste, mais vous pouvez modifier le contenu de la liste vers laquelle elle pointe. al -> [v1, v2, v3] al ne peut pas être modifié mais v1, v2 et v3 peuvent être modifiés. Mike a tout à fait raison de dire que cela rend tout mutable parce que dans notre terminologie, al * est * la liste et non le pointeur de la liste. – charlieb
+1 très belle réponse. –