2014-03-16 3 views
12

Я понимаю концепцию локальных и глобальных переменных в Python, но у меня просто возникает вопрос, почему ошибка возникает так, как она есть в следующем коде. Python выполняет коды по строкам, поэтому он не знает, что a является локальной переменной, пока не прочитает строку 5. Остается ли Python вернуться к одной строке и пометить ее как ошибку после попытки выполнить строку 5?Python local vs global variables

a=0 

def test(): 
    print a #line 4, Error : local variable 'a' referenced before assignment 
    a=0  #line 5 

test() 

ответ

12

Настройка и тестирование

проанализировать ваш вопрос, давайте создадим две отдельные тестовые функции, которые копируют ваш вопрос:

a=0 

def test1(): 
    print(a) 

test1() 

отпечатки 0. Таким образом, вызов этой функции не является проблемой, но на следующей функции:

def test2(): 
    print(a) # Error : local variable 'a' referenced before assignment 
    a=0 

test2() 

Мы получаем ошибку:

Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 2, in test2 
UnboundLocalError: local variable 'a' referenced before assignment 

Разборка

Мы можем разобрать две функции (первый Python 2):

>>> import dis 
>>> dis.dis(test1) 
    2   0 LOAD_GLOBAL    0 (a) 
       3 PRINT_ITEM   
       4 PRINT_NEWLINE  
       5 LOAD_CONST    0 (None) 
       8 RETURN_VALUE   

И мы видим, что первая функция автоматически загружает глобальную a, а второй функции:

>>> dis.dis(test2) 
    2   0 LOAD_FAST    0 (a) 
       3 PRINT_ITEM   
       4 PRINT_NEWLINE  

    3   5 LOAD_CONST    1 (0) 
       8 STORE_FAST    0 (a) 
      11 LOAD_CONST    0 (None) 
      14 RETURN_VALUE  

, видя, что a назначается внутри него, пытается LOAD_FAST от местных жителей (как вопрос оптимизации, как функции . предварительно компилируются в байт-код перед запуском)

Если мы запустим это в Python 3, мы видим почти тот же эффект:

>>> test2() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 2, in test2 
UnboundLocalError: local variable 'a' referenced before assignment 
>>> 
>>> import dis 
>>> dis.dis(test1) 
    2   0 LOAD_GLOBAL    0 (print) 
       3 LOAD_GLOBAL    1 (a) 
       6 CALL_FUNCTION   1 (1 positional, 0 keyword pair) 
       9 POP_TOP    
      10 LOAD_CONST    0 (None) 
      13 RETURN_VALUE  

>>> dis.dis() # disassembles the last stack trace 
    2   0 LOAD_GLOBAL    0 (print) 
    -->  3 LOAD_FAST    0 (a) 
       6 CALL_FUNCTION   1 (1 positional, 0 keyword pair) 
       9 POP_TOP    

    3   10 LOAD_CONST    1 (0) 
      13 STORE_FAST    0 (a) 
      16 LOAD_CONST    0 (None) 
      19 RETURN_VALUE   

Мы снова видим нашу ошибку на LOAD_FAST.

2

Краткое объяснение:

a переменная связана с функцией test. Когда вы пытаетесь распечатать его, Python выдает ошибку, потому что локальная переменная a будет инициализирована позже. Но если убрать a=0, код будет выполняться без каких-либо проблем и выходе 0.

Longer объяснение

интерпретатор Python начинает искать переменную с именем a из локальной области видимости. Он видит, что a действительно объявлен внутри функции и инициализирован только на пятой строке. Как только он будет найден, поиск завершен.

Когда он пытается обработать print a (четвертая строка), он говорит: «О, мальчик, мне нужно напечатать переменную, которая еще не инициализирована, я бы лучше выбросил ошибку».

Объяснения основано на байткоде функции в

Если запустить этот код:

import dis 

a = 0 

def test(): 
    print a #line 4, Error : local variable 'a' referenced before assignment 
    a = 0 #line 5 

dis.dis(test) 

вы получите этот результат:

6   0 LOAD_FAST    0 (a) 
       3 PRINT_ITEM   
       4 PRINT_NEWLINE  

    7   5 LOAD_CONST    1 (0) 
       8 STORE_FAST    0 (a) 
      11 LOAD_CONST    0 (None) 
      14 RETURN_VALUE   

Объяснения на непонятных части выше :

  • LOAD_FAST означает, что ссылка a выталкивается в стек.
  • STORE_FAST означает, что Python присваивает 0 (от LOAD_CONST) к локальной переменной a

Таким образом, проблема заключается в том, что LOAD_FAST идет перед STORE_FAST.

4

Это потому, что в python вам нужно сообщить, что вы собираетесь изменить значение глобальной переменной. Вы что, как:

def test(): 
    global a 
    print a #line 4, Error : local variable 'a' referenced before assignment 
    a=0  #line 5 

С global a, вы можете изменять переменные в функции. Вы можете посмотреть на это:

6

Python не выполняет строку за строкой в ​​представленном вами коде функции. Он должен сначала разобрать его как блок исполнения. Он решает, является ли переменная локальной или глобальной в зависимости от того, написана ли она на (функциональном) локальном уровне. Как это имеет место, он решает, что переменная локальна, следовательно, ошибка.