2

Python の実行で予期しない動作が発生します。

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

コントロールが else ステートメントに入らないため、このコードは SyntaxError を発生させません。C++ などのコンパイル済み言語では、エラーが発生します。Javaでも未使用コードはエラーです。しかし、Python ではありません。

この場合、次のようになります。

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

ここで指定されているように、print ステートメントは UnboundLocalError を発生させます。前のロジックによれば、このエラーは、コントロールが x+=1 に遭遇するまで発生しないはずです。しかし、他のコンパイル済み言語と同様に、そうです。

では、コードがいつコンパイルまたは解釈されて実行されるかを判断する方法は?

編集: バイトコード .pyc ファイルにコンパイルされてから解釈される場合。では、最初の例の else ステートメントが検出されないのはなぜですか?

4

4 に答える 4

2

反対。Python は、実行前にソースをバイト コードにコンパイルします。最初のケースでは、コンパイル フェーズ中に構文エラーが発生します。

2 番目のケースでは、コンパイラは が関数内で変更されていることを認識し、関数オブジェクトxにバインドします。x関数の名前空間は関数が呼び出されるたびに作成されますが、変数は割り当てられたときにのみ表示されます。そのpythonを実行したときだけ、print(x)割り当てられていないローカル変数を要求していることに気づきます。これは、すべての実行パスが変数を適切に設定するわけではない場合によくあるバグです。

例を少し変更すると、ローカル変数が設定される場合と設定されない場合があります。設定すると、変数がローカルに表示され、印刷が機能します。設定されていない場合、変数はローカルに存在せず、出力は失敗します。

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
于 2016-11-27T07:50:47.267 に答える
1

Doug と Jim からの回答を読んだ後、これがどのように機能するかについてのアイデアがあると思います。まず第一に、例は REPL (Ipython、デフォルト) で動作します

ファイル: これをファイルに書き込む場合:

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()

そしてブーム!すべてがバラバラになり、 print(x) ステートメントで UnboundLocalError が発生します。つまり、バイトコードが存在します。

では、ここで何が起こっているのでしょうか。

Python は、変数の 1 つの出現を見つけると、最初にそれらすべてを読み取ることによって、その動作を最適化しようとします。したがって、コードが print(x) に遭遇した 2 番目の例では、x のすべての操作を検索しようとします。すぐにステートメント x+=1 が見つかります。ローカル スコープには x の言及がなく、明示的に言及されていない場合、python はグローバル スコープで変数を検索しないため、次のようになります。

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 は実行されませんでしたが、print ステートメントが x を出力し、別の参照 (x+=1) が問題だったため、値を出力する前にエラーが発生しました。最初のケースは、REPL の SyntaxError がなくても問題なく動作しました。これは、else ステートメント内を調べる必要がなかったためです。

于 2016-11-27T13:28:41.833 に答える
1

常に解釈されたとおりに実行されます。ただし、バイトコード ファイルを生成する最初のステップとして、ファイル全体に対して構文チェッカーが呼び出されます。

Python 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 で「実行時」構文エラーが発生することはあり得ません。これを実現する唯一の方法は、構文エラーのあるモジュールを動的にインポートすることです。

あなたの質問を理解できたかどうかわかりませんが、2 番目のケースのエラーは実行時エラーです。int x = 0; y = 10/x;C で行うようなものです。変数のスコープ (「この時点で 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
于 2016-11-27T07:29:12.633 に答える
0

いくつかの短い対話型 REPL (Python のデフォルト REPL ではない) を介してこれを実行している場合、これを実際にエラーなしで実行できる可能性があります (IPythonたとえば、s' qtconsole では問題なしで実行できます)。これが許可される理由は、REPL とその実装のみに依存します。

Python では、これ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

文法では具体的には許可されていません.文字列リテラルのみがそれらの間にスペースを入れて配置することが許可され( Pythonは後で連結します)、名前は許可されません(それ自体の単一の名前はもちろん許可されます). つまり、これは解析段階で失敗します。

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 は、2 つの名前がスペースで区切られている場合、何をすべきかわかりません。スペースは、(strリテラルを除いて) 操作を意味するものではありません。

于 2016-11-27T10:08:46.427 に答える