2

Я получаю неожиданное поведение выполнения python.Компиляция против интерпретации, Python имеет неожиданное поведение

if True: 
    print("Hello") 
else: 
    I am an error. what can you do about it? 

Теперь этот код не поднимает SyntaxError потому что контроль никогда не переходит в заявлении еще. В скомпилированных языках, таких как C++, появляется ошибка. Даже в Java неиспользуемый код является ошибкой. Но не в Python.

Теперь в этом случае:

x = 10 
def foo(): 
    print(x) 
    x += 1 

Оператор печати поднимает UnboundLocalError, как указано here. Согласно предыдущей логике, эта ошибка не должна быть до тех пор, пока элемент управления не встретит x + = 1. Но это происходит, как и на любом компилированном языке.

Затем, как определить, когда код будет выполняться как скомпилированный или интерпретируемый?

Редактировать: Если он скомпилирован в файл байт-кода .pyc и затем интерпретируется. Тогда почему первый оператор примера else не обнаружен?

+1

В первом примере это синтаксическая ошибка. Если вы поместите его в .py-файл и попытаетесь его выполнить, вы увидите. – tdelaney

+1

Я думаю, что у вас есть вопрос, что вы * выполняете код в оболочке интерпретатора, то есть REPL. –

+0

Если мы поместим оба из них в интерактивную оболочку .. возникает расхождение. Вы знаете, почему? –

ответ

1

Он всегда работает как интерпретируемый; но проверка синтаксиса вызывается во всем файле как первый шаг, который генерирует файл байт-кода.

В обоих питона 2,7 и 3,5 код, который вы поместили в верхней части приведет к синтаксической ошибке:

python3 junk.py 
    File "junk.py", line 4 
    I am an error. what can you do about it? 
      ^
SyntaxError: invalid syntax 

Это не должно быть возможным, чтобы получить синтаксическую ошибку «выполнения» в Python; единственный способ добиться этого - динамически импортировать модуль с синтаксической ошибкой.

Я не уверен, что понял ваш вопрос, но ошибка во втором случае - ошибка времени выполнения; это как делать int x = 0; y = 10/x; в C; переменная scope («существует ли x в этой точке?») не разрешается во время синтаксического анализа в python.

-

Редактировать; вот свалка из моего терминала:

Clank:tmp doug$ cat junk.py 
if True: 
    print("Hello") 
else: 
    I am an error. what can you do about it? 

Clank:tmp doug$ python junk.py 
    File "junk.py", line 4 
    I am an error. what can you do about it? 
    ^
SyntaxError: invalid syntax 

Clank:tmp doug$ python3 junk.py 
    File "junk.py", line 4 
    I am an error. what can you do about it? 
    ^
SyntaxError: invalid syntax 
+0

Можете ли вы показать мне код, потому что я знаю, что первый из них не вызывает синтаксическую ошибку. Ошибка происходит только тогда, когда элемент управления достигает инструкции. И в этом моя проблема. –

+0

@AbhishekBera Добавил его в вопрос. Я озадачен тем, как вы можете заставить это работать, не будучи синтаксической ошибкой. Можете ли вы предоставить какие-либо другие данные? Какую версию python вы используете и какую платформу? – Doug

+0

Хорошо .. Думаю, я мог бы понять, что пошло не так. Когда я написал первый в живом интерпретаторе, он отлично работает. Но когда я написал код в файле, наконец появился SyntaxError. Второй - затенение области. Существует переменная x в глобальной области видимости, но всякий раз, когда она сталкивается с редактированием, подобным x + = 1, он ищет x только в локальной области, а все остальные удаляются. Поскольку в локальной области нет переменной, мы имеем UnboundLocalError. –

2

Противоположный. Python компилирует исходный код в байтовый код перед выполнением. Первый случай приведет к возникновению синтаксической ошибки во время фазы компиляции.

Во втором случае компилятор видит, что x изменен в функции, поэтому он связывает x с объектом функции. Пространство имен функций создается каждый раз, когда вызывается функция, но переменная появляется только тогда, когда она была назначена. Его единственный, когда вы выполняете print(x), что python понимает, что вы запрашиваете локальную переменную, которая не была назначена. Это обычная ошибка, когда не все пути выполнения задают переменную, как они должны.

Немного изменяя пример, иногда устанавливается локальная переменная, в других случаях это не так. Когда установлено, вы видите переменную в locals и печать работает. Если этот параметр не установлен, переменная не находится в локальных сетях, и печать завершается с ошибкой.

x = 10 
def foo(val): 
    if val: 
     x = 1 
    print(val, 'before', locals()) 
    print(x) 
    print(val, 'after') 
    x += 1 

foo(True) 
foo(False) 

Выход

True before {'val': True, 'x': 1} 
1 
True after 
False before {'val': False} 
Traceback (most recent call last): 
    File "o.py", line 11, in <module> 
    foo(False) 
    File "o.py", line 6, in foo 
    print(x) 
UnboundLocalError: local variable 'x' referenced before assignment 
0

Если вы работаете в этом с помощью интерактивных РЕПЛ некоторые короткие (и не питоны по умолчанию REPL) вы могли бы получать это на самом деле выполнить без ошибок (qtconsole IPython S'позволяет например, без проблем). Почему это разрешено, зависит исключительно от REPL и его реализации.

В Python это is a SyntaxError; там не может быть никакого байткодом сгенерированными для него:

s =""" 
i= 1 
if i: 
    print("Hello") 
else: 
    I am an error. what can you do about it? 
""" 
c = compile(s, '', mode='exec') 
    File "<string>", line 6 
    I am an error. what can you do about it? 
    ^
SyntaxError: invalid syntax 

Грамматика конкретно не позволяет, только строковые литералы могут быть размещены с промежутками между ними (which Python later concatenates), имена не являются (конечно, разрешено одно имя на своем собственном языке). Короче говоря, это не удается в разборе фазе:

from parser import suite 
st = suite(s) 
    File "<string>", line 6 
    I am an error. what can you do about it? 
    ^
SyntaxError: invalid syntax 

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

+0

Да, я использую Ipython. Но даже если я сделаю оба кода в REPL. Существует расхождение между первым и вторым. Мой вопрос - почему это несоответствие. На самом деле, я не могу получить уникальную теорию для объяснения обоих случаев. Я также пробовал в Python2.7 и 3.5 по умолчанию REPL, и результаты были такими же ... Почему два оператора ведут себя по-другому? –

1

Хорошо, прочитав ответы от Дуга и Джима, я думаю, у меня есть идея о том, как это работает. Прежде всего из примеров работы в REPL (IPython, по умолчанию)

Files: Если вы пишете это в файле:

if True: 
    print("Hi") 
else: 
    I am an error. What can you do about it? 

и запустить файл, он будет бросать SyntaxError. Это доказывает, что всякий раз, когда мы выполняем код python из файла, он генерирует байт-код и, поскольку оператор в else не является допустимым выражением python, мы получаем SyntaxError.

REPL: С REPL все становится немного зависимым. В интерпретаторе python, если вы набираете

>>>def foo(): 
     if True: 
      print("Hey") 
     else: 
      I am an error. What can you do about it? 
>>>foo() 
Hey 

Успешное выполнение означает отсутствие байт кода справа? Оставайтесь на линии.

Если вы пишете это:

>>>x = 10 
>>>def foo(): 
     print(x) 
     x += 1 
>>>foo() 

И Boom! все разваливается, вы получаете команду UnboundLocalError в print (x). Что означает байт-код.

Так что же здесь происходит?

Если python находит одно единственное вхождение переменной, он пытается оптимизировать свою работу, сначала прочитав все из них. Итак, во втором примере, когда код встречает печать (x), он пытается найти все операции над x. Вскоре он находит утверждение x + = 1.Поскольку нет никакого упоминания о х в локальной области и питон никогда не ищет переменную в глобальном масштабе, если не упомянуто явно, мы имеем

UnboundLocalError: local variable 'x' is referenced before assignment 

убедительное доказательство

Если мы пишем что-то вроде этого:

>>>x = 10 
>>>def foo(): 
     if True: 
      print(x) 
     else: 
      x+=1 
>>>foo() 
UnboundLocalError: local variable 'x' referenced before assignment 

Это все!

x + = 1 никогда не будет выполнен, но поскольку оператор печати печатает x, а другая ссылка (x + = 1) была проблемой, произошла ошибка, возникшая перед печатью значения. Первый случай работал отлично без SyntaxError в REPL, потому что он никогда не беспокоился о том, чтобы смотреть в выражение else, потому что это никогда не имело значения.