ソースコードを見ると、 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")