2017-04-24 9 views
14
$ echo "Your code is bad and you should feel bad" > "<stdin>" 
$ python 
Python 3.6.0 (default, Dec 28 2016, 19:53:26) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux 
Type "help", "copyright", "credits" or "license" for more information. 
>>> 2 + '2' 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    Your code is bad and you should feel bad 
TypeError: unsupported operand type(s) for +: 'int' and 'str' 

なぜPythonは文字列"<stdin>"をそのファイル名と一致するファイルと混同しますか?私は、処理されない例外が発生した場合、Pythonがディスクからファイルを読み込もうとしませんでした。トレースバックを印刷するときに、現在のディレクトリからPythonが読み込まれるのはなぜですか?

また"<string>"ファイル名でそれを得ることができます。

$ echo "pining for the fjords" > "<string>" 
$ python -c 'wat' 
Traceback (most recent call last): 
    File "<string>", line 1, in <module> 
    pining for the fjords 
NameError: name 'wat' is not defined 

は、その動作を防ぐ方法はありますか、REPLにハードコードされましたか?

+8

ああ、かわいいバグです。あなたはそれを報告すべきです。 – kindall

答えて

7

Pythonは、コンパイルされたバイトコードに対応するソースコードを追跡しません。たとえば、モジュールが.pycファイルからロードされた場合など、トレースバックを出力する必要があるまで、そのソースコードを読み取ることさえできないことがあります。

Pythonがトレースバックを印刷する必要がある場合、それは関係するすべてのスタックフレームに対応するソースコードを見つけることを試みるときです。スタックトレースに表示されるファイル名と行番号は、すべてPythonが続行する必要があります。 tracebackモジュールを使用していた場合、コードパスはlinecacheのセクションを通過しますが、excludes filenames starting and ending with < and >ですが、デフォルトのsys.excepthookはそのパスを通過しません。

default sys.excepthookは、最終的には個々のソース行を表示する_Py_DisplaySourceLineを使用して巻き取るネイティブコールPyErr_Display、通過します。 _Py_DisplaySourceLineは、現在の作業ディレクトリ(何らかの理由で間違った最適化?)でファイルを無条件に検索しようとしましたが、を呼び出して、作業ディレクトリにそれがない場合はsys.pathという名前のファイルを検索します。通常、<stdin>または<string>というファイルは見つからず、ファイルが見つからない場合は印刷ソースコードをスキップしますが、見つかった場合はそのファイルから印刷します。

私は当初、-I flagでPythonを実行し、これを隔離モードにすることでこれを防ぐことができたと考えました。隔離モードの効果の1つは、スクリプトのディレクトリをsys.pathから削除することです。実験ではこれが変更されていないことが証明されました。つまり、_Py_DisplaySourceLineは何があっても作業ディレクトリを試しています。

linecacheのように、ネイティブコードパスで<>ファイル名を除外することでこれを解決するのはかなり簡単でしょう。現在のディレクトリで無条件にファイルを検索するコードも変更する必要があります。

+0

linecache( 'linecache.updatecache()')を更新しようとしたときに 'filename.startswith(" <")とfilename.endswith("> ")という特殊なケースが既に存在しているので、 to checkcache()。 – pbuck

+0

@pbuck:そうです、そうです。私は、このコードパスは実際には 'linecache'を経由しないと考えています。 sys.modulesの '' linecache 'は、Python 3で試してみるとキャッチされなかった例外の前後に 'False'と報告します。 – user2357112

+0

' -I'フラグで実行すると、 'sys.path [0]'の空文字列は避けられますが、ディスクからのトレースバックの動作を変更しません。 – wim

関連する問題