2013-06-21 3 views
6

Я читаю этот article о декораторе.переменная переменной python во вложенных функциях

В Шаг 8, есть функция определяется как:

def outer(): 
    x = 1 
    def inner(): 
     print x # 1 
    return inner 

и если мы запустим его:

>>> foo = outer() 
>>> foo.func_closure # doctest: +ELLIPSIS 

не печатает х. Согласно объяснению:

Все работает в соответствии с правилами обзора Python - x является локальной переменной в нашей внешней функции. Когда внутренний печатает x в точке # 1, Python ищет локальную переменную, внутреннюю и не находящую ее, выглядит в области видимости, которая является внешней функцией, находящейся там.

Но как насчет вещей с точки зрения переменного времени жизни? Наша переменная является локальной для внешней функции, что означает, что она существует только во время работы внешней функции. Мы не можем называть внутренний до после возврата внешнего, поэтому в соответствии с нашей моделью, как работает Python , x не должен существовать больше к тому времени, когда мы вызываем внутренний и, возможно, , должна произойти некорректная ошибка времени выполнения.

Однако я не совсем понимаю, что означает второй абзац.

Я понимаю, что inner() действительно получает значение x, но почему он не печатает x out?

благодаря

UPDATE:

Спасибо всем за ответы. Теперь я понимаю причину. «вернуть внутренний» просто указатель на внутренний(), но он не получает выполняется, поэтому внутренняя() не печатает х, как это не вызывается вообще

ответ

2

Вы не звоните inner. Вы вызвали outer, который возвращает inner, но не называя его. Если вы хотите позвонить inner, сделайте foo() (так как вы оценили результат outer() на имя foo).

Этот параграф, который вы цитируете, является своего рода касательным к этой проблеме. Вы говорите, что поняли, почему inner получает значение x, что и объясняет этот параграф. В принципе, если локальная переменная используется во вложенной функции и возвращается вложенная функция, значение переменной сохраняется вместе с возвращаемой функцией, даже если область, в которой эта переменная была определена, больше не активна. Обычно x исчезнет после завершения outer, потому что x является только локальным для outer. Но outer возвращает inner, которому по-прежнему нужен доступ к x.Таким образом, x обернуто в так называемое закрытие, поэтому к нему еще можно получить доступ к inner.

+0

OP также спрашивают, почему 'x' все еще существует – jamylak

+0

@jamylak: Это мне не ясно, является ли он или нет. Он говорит, что не понимает этот цитируемый параграф, но также говорит, что он понимает, как 'inner' имеет доступ к' x'. – BrenBarn

+0

в любом случае, теперь вы ясно дали – jamylak

7

Я понимаю, что внутри() действительно значение x, но почему оно не печатает x out?

Он ничего не распечатывает, потому что вы еще не вызвали внутреннюю функцию.

>>> def outer(): 
     x = 1 
     def inner(): 
       print x # 1 
     return inner 
...  
>>> func = outer() 
>>> func    
<function inner at 0xb61e280c> 
>>> func() 
1 

Это называется closure, то есть, даже если внешняя функция не в стеке (закончил выполнение) больше, но до сих пор внутренняя функция, которая была возвращена из нее помнит, что это состояние. (Т.е. значение x)

>>> def outer(): 
      x = 1 
      y = 2 
      def inner(): 
        z=3 
        print x 
      return inner 
...  
>>> func = outer() 
>>> func.func_code.co_freevars #returns the variables that were used in closure 
('x',) 

с source code о том, как питон решает, что это закрытие или нет:

459 if len(code.co_freevars) == 0: 
    460  closure = NULL 
    461 else: 
    462  len(closure) == len(code.co_freevars) 

В py3.x вы можете аль поэтому измените значение x, используя инструкцию nonlocal внутри внутренней функции.

>>> def outer(): 
     x = 1 
     def inner(): 
      nonlocal x 
      x += 1 
      print (x) 
     return inner 
...  
>>> func = outer() 
>>> func() 
2 
>>> func() 
3 
>>> func() 
4 
+2

+1 для оператора '' nonlocal'' – Tregoreg

Смежные вопросы