1

当我exec open("tx.py")在 Python 中对非 ASCII 文件使用时,出现如下错误:

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 会愉快地编译该文件。我怎么SyntaxError能从compile(...)得到同样的结果?

请注意,我在这里的目标不是修复SyntaxError,而是使compile(...)的行为方式与exec相同。

4

2 回答 2

4

查看源代码, usingexec以 call 结尾PyTokenizer_FromFile,而PyTokenizer_FromString用于compile(). 这些在标记器的设置方式上有所不同。

标记器从PyTokenizer_FromFile一个空缓冲区开始,并调用fp_readl函数来填充标记器缓冲区,这可能会触发您看到的异常(如果标记器没有看到编码声明并且看到了非 ASCII 字符) . 然后将文件内容重新编码为 UTF8 并由分词器处理,以便于分词。令牌稍后被重新编码为原始编解码器。

使用时PyTokenizer_FromString,缓冲区设置为传入的字符串。检查字符串是否有 BOM 和符合 PEP 263 的注释,就像正在读取文件一样,但如果没有设置这样的编解码器,则字符串只是由分词器按原样处理,不会发生重新编码。在这种情况下,标记器的encoding字段为空,就像 ASCII 文件一样。初始化缓冲区,没有文件对象,没有调用,fp_readl也永远不会引发异常。

由于这些差异,没有办法强制compile()表现得完全像exec. 您必须手动执行相同的测试:

  • 检查第一个字节中的 BOM;测试codecs.BOM_*常数
  • 检查coding前两行中的注释。
  • 如果缺少这些,请尝试从 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 回答
1

有了这条线:

tx = compile(open("tx.py").read().decode('ascii'), "tx.py", "exec")

或者 :

import codecs
tx = compile(codecs.open("tx.py", encoding='ascii').read(), "tx.py", "exec")

我收到了这个错误:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe9 in position 18: ordinal not   in range(128)

这是我离你的 SynthaxError 越近的地方。

编辑:您可以编写自己的自定义编译并按照您的意愿格式化预期的错误:

def custom_compile(source, *args, **kwargs):
    try:
        return compile(source.decode('ascii'), *args, **kwargs)
    except UnicodeDecodeError as error:
        raise SyntaxError(error)

tx = custom_compile(open("tx.py").read(), "tx.py", "exec")

错误 :

SyntaxError: 'ascii' codec can't decode byte 0xe9 in position 17: ordinal not in range(128)
于 2013-11-14T10:33:54.060 回答