Python与非Latin-1 PYTHONHOME路径

10

在我的情况下,我将Python嵌入到我的应用程序中。当应用程序路径包含非Latin-1字符时,Py_Initialize会在内部调用exit(1)(更多信息稍后)。

因此,我检查是否可以使用标准解释器可执行文件复现此问题。

Windows上的Python-2.7.x似乎无法在PYTHONHOME路径包含Latin-1字符集之外的字符时工作。问题在于找不到并导入模块site。由于变音符好像可以正常工作,那么实际的限制是什么?只支持Latin-1吗?为什么在OSX上可以工作?

C:\Users\ъ\Python27\python.exe    // fails to start (KOI8-R)
         ^
C:\Users\ġ\Python27\python.exe    // fails to start (latin-3)
         ^
C:\Users\ä\Python27\python.exe    // works fine (latin-1)
         ^

有什么想法吗?

背景:

我还没有逐步分析代码,但是当 site 不可用时,Python 2.6 和 Python 2.7 的行为也不同。Py 2.6 只会打印一条消息,而Py 2.7则无法启动。

static void
initsite(void)
{
    PyObject *m;
    m = PyImport_ImportModule("site");
    if (m == NULL) {
        ...

        // Python 2.7 and later
        exit(1);

        // Python 2.6 and prior
        PyFile_WriteString("'import site' failed; traceback:\n", f);
    }
    ...
}

Python 2.7: https://github.com/enthought/Python-2.7.3/blob/master/Python/pythonrun.c#L725

Python 2.6: https://github.com/python-git/python/blob/master/Python/pythonrun.c#L705


1
你尝试过使用Python 3吗?他们重新设计了Unicode处理方式,更加简洁。我的建议是尽可能使用3,只有在必要时才使用2。 - A. L. Flanagan
在Python 3中,它(应该)可以工作,是的。我必须坚持使用Python 2,因为这是我们嵌入到软件中的版本,不过这将来会改变。 - HelloWorld
你能详细说明一下如何在你的应用程序中“嵌入”Python吗?是通过从C/C++中调用它来实现的吗?你使用的机制是什么?你设置PYTHONHOME吗?如果是这样,你是如何设置的?顺便说一句,在Windows、Mac和Linux/POSIX上,操作系统文件系统对Unicode路径的处理行为有很大的差异。在CPython 2中处理这个问题有时需要进行一些调整...虽然我曾经成功地解决过这个问题。 - Philippe Ombredanne
使用C API中的Py_Initialize函数。我尝试了PYTHOMHOME和相应的C函数(Py_SetPath, Py_SetPythonhome等),但都没有成功。顺便说一下,如果在给定的路径安装Python 2.7(未嵌入),也无法正常工作。 - HelloWorld
MS Windows与OS X不同之处在于其基本字符集为UTF-16。对于旧代码,它也提供了一个使用单字节字符串的“ANSI”API,但无法表示整个Unicode范围。我几乎可以肯定Python 2永远不会升级到使用完全支持Unicode的win32 API,所以除非你至少升级到Python 3,否则任何麻烦都是徒劳的。 - Ulrich Eckhardt
2个回答

2
我认为问题在于Python2内部将所有内容处理为字节字符串,使用的是平台系统编码(在西欧地区)CP1252,这是Latin-1的一种变体。因此,当PYTHONHOME路径包含其他字符时,它无法正确处理,这并不奇怪。
但是,在我年轻的时候,我习惯于使用旧的MS/DOS文件8.3格式...
我仍然可以在Windows 7上通过控制台(CMD.EXE)窗口中的DIR /X命令看到它们(并使用它们)。该格式仅使用ASCII大写字符和波浪号(~),因此它可以用作解决方法:只需在环境变量PYTHONHOME中声明8.3路径,并使用该8.3路径启动python。
顺便提一下,建议PYTHONHOME使用不包含特殊字符或空格的路径。它可能有效,但可能会导致其他模块出现问题。

1
如果在俄罗斯的Windows上运行,因为它们具有相应的系统代码页(猜测是CP125 1),我完全同意。但是,在那里它也失败了。 - HelloWorld
仅供完整性参考:对于俄语操作系统,控制台代码页为866。 - HelloWorld
如果缺少8.3名称,请检查它们是否被禁用:fsutil behavior query Disable8dot3 C:。请注意,启用8.3名称仅会影响随后创建的新文件,而不会影响现有文件。您还可以尝试使用mklink创建仅限ASCII的硬链接、符号链接或联接。 - Eryk Sun

2

查看PyImport_ImportModule函数版本2.7的定义如下:

PyObject *
PyImport_ImportModule(const char *name)
{
    PyObject *pname;
    PyObject *result;

    pname = PyString_FromString(name);
    if (pname == NULL)
        return NULL;
    result = PyImport_Import(pname);
    Py_DECREF(pname);
    return result;
}

当查看与版本3.5相关的PyImport_ImportModule函数时,结果相同。

pname = PyUnicode_FromString(name);

替代

pname = PyString_FromString(name);

您可以查看 PyString_FromString 的代码 PyUnicode_FromString 的代码,但显然Python 2不使用Unicode,而Python 3则使用Unicode。 我没有找到确切的地方或原因导致了您所描述的行为。

函数 PyImport_Import(module_name)(版本2.7)仅按以下方式使用 module_name

r = PyObject_CallFunction(import, "OOOOi", module_name, globals,
                          globals, silly_list, 0, NULL);

将责任传递下去...


仅提供一些背景信息:Python 2 可以处理 Unicode,但是在 Python 3 中,Unicode 处理方式已经完全重构。Python 2 使用“最佳猜测”解码方法,如果猜错了,就会出现各种问题。Python 3 将 Unicode 字符串视为字符串,并将编码的 Unicode 视为字节数组,如果需要,强制您显式处理转换。 - A. L. Flanagan
我预计问题出现在 PyImport_Import 的某个地方。我猜测路径中包含 Unicode 字符的目录查找失败了。正如提到的那样,我还没有进行调试。至少在这个阶段,仍然支持 Latin-1。 - HelloWorld

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接