1

Python で非 ASCII ファイルを使用するexec open("tx.py")と、次のようなエラーが発生します。

SyntaxError: Non-ASCII character '\xc3' in file tx.py on line 1, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details

しかし、compile(open("tx.py").read(), "tx.py", "exec")そのようなエラーは発生せず、Python 2.7 は問題なくファイルをコンパイルします。compile(...)SyntaxErrorからこれと同じものを取得するにはどうすればよいですか?

ここでの私の目標は を修正することではなく、 compile(...)をexecと同じように動作SyntaxErrorさせることであることに注意してください。

4

2 に答える 2

4

ソースコードを見ると、 usingexecは を呼び出すことPyTokenizer_FromFileになり、 whilePyTokenizer_FromStringは for に使用されcompile()ます。これらは、トークナイザーの設定方法が異なります。

PyTokenizer_FromFileトークナイザーは空のバッファーで開始し、トークナイザー バッファーを埋めるために関数が呼び出されます。これによりfp_readl、見た例外がトリガーされる可能性があります (トークナイザーがエンコード宣言を見ておらず、非 ASCII 文字が見られた場合)。 . 次に、トークン化を容易にするために、ファイルの内容は UTF8 に再コード化され、トークナイザーによってそのように処理されます。トークンは後で元のコーデックに再エンコードされます。

使用するPyTokenizer_FromStringと、バッファは渡された文字列に設定されます。文字列は、ファイルの読み取り時と同様に、BOM と PEP 263 準拠のコメントについてチェックされますが、そのようなコーデックが設定されていない場合、文字列は単にトークナイザーによってそのまま処理され、再エンコードは行われません。そのencoding場合、ASCII ファイルの場合と同様に、トークナイザーのフィールドは空のままになります。バッファーが初期化されていて、ファイル オブジェクトがない場合、呼び出しfp_readlは行われず、例外は発生しません。

これらの違いにより、 とまったく同じように動作するように強制する方法はありません。同じテストを手動で行う必要があります。compile()exec

  • 最初のバイトで BOM を確認します。codecs.BOM_*定数に対するテスト
  • coding最初の 2 行のコメントを確認します。
  • これらが欠落している場合は、ASCII からのデコードを試みSyntaxError、デコードが失敗した場合は手動で例外をスローします。
import codecs
import re
_boms = (codecs.BOM_UTF8,) + tuple(v for k, v in vars(codecs).iteritems() if k.startswith('BOM_') and k[-3:] in ('_LE', '_BE'))
_coding_line = re.compile('\s*#\s*coding[:=]\s*[-\w.]+').match

def compile_precheck(string):
    if string.startswith(_boms):
        return
    for line in string.splitlines()[:2]:
        if _coding_line(line)
            return
    try:
        string.decode('ascii')
    except UnicodeDecodeError:
        raise SyntaxError(
            "Non-ASCII character in source string but no encoding declared")

source = open("tx.py").read()
compile_precheck(source)
tx = compile(source, "tx.py", "exec")
于 2013-11-14T11:49:24.753 に答える