接前面Python源码笔记之Py_InitializeEx,尝试看看Python中用到的一些Path (这部分东西太乱了...具体见PC/getpathp.c 和 Modules/getpath.c 中的注释)。
一个Python程序要有运行,必须要能找到 .py/.pyc/.pyo/.pyd/.so 等,如何找到这些模块,还真是个问题:
sys.executable |
可执行程序完整路径(其他函数可据此查找python运行时需要的库) |
|
sys.prefix |
平台无关文件 |
Python安装路径,用来生成标准库搜索路径 |
sys.exec_prefix |
平台相关文件 |
|
sys.path |
模块搜索路径 |
prefix 和 exec_prefix,平时用,几乎总是一样的,应该不用细分。
常见默认值 |
||
Unix (pure) |
prefix/lib/pythonX.Y |
/usr/local/lib/pythonX.Y |
Unix (non-pure) |
exec-prefix/lib/pythonX.Y/ |
/usr/local/lib/pythonX.Y |
Windows |
prefix\Lib |
C:\PythonXY\Lib\ |
这4个均在Py_InitializeEx进行初始化:
初始值 |
|
executable |
Py_GetProgramFullPath() |
prefix |
Py_GetPrefix() |
exec_prefix |
Py_GetExecPrefix() |
path |
Py_GetPath() |
_PySys_Init()
PyObject * _PySys_Init(void) { SET_SYS_FROM_STRING("executable", PyUnicode_FromWideChar( Py_GetProgramFullPath(), -1)); SET_SYS_FROM_STRING("prefix", PyUnicode_FromWideChar(Py_GetPrefix(), -1)); SET_SYS_FROM_STRING("exec_prefix", PyUnicode_FromWideChar(Py_GetExecPrefix(), -1)); ...
PySys_SetPath(Py_GetPath());
void PySys_SetPath(const wchar_t *path) { PyObject *v; if ((v = makepathobject(path, DELIM)) == NULL) Py_FatalError("can't create sys.path"); if (PySys_SetObject("path", v) != 0) Py_FatalError("can't assign sys.path"); Py_DECREF(v); }
与这些path相关的有两个环境变量非常关键:
用来指定 prefix 和 exec_prefix 的值,格式:"ThePrefixPath" 或 "ThePrefixPath:TheExec_prefixPath"。注意,指定两个路径时,用冒号分割。
如果使用 Py_SetPythonHome() 设置了home值,则不会使用环境变量指定的值!
设置模块的默认搜索路径,路径间分隔符和平台相关:Windows下分号,其他平台冒号。
除了前面的环境变量,下面3个函数也很重要(在Py_InitializeEx之前调用)
Py_SetProgramName()
Py_SetPythonHome()
Py_SetPath()
注意:使用Py_SetPath()以后,prefix和exec_prefix都将为空。Manual中说多个路径采用分号分割!这是错的,应该是和平台相关,Windows下用分号,其他平台冒号。
大致分两步:
然后,在prefix和exec_prefix上面追加libpath(比如lib/pythonXX/)以及宏PYTHONPATH中指定的路径(比如在linux下,可能是L":plat-linux2")
prefix 的确定(linux下):
如果PYTHONHOME被设置(无论是环境变量,还是Py_SetPythonHome()),则无条件使用它。
否则,按照可执行程序所在路径(Py_SetProgramName)依次往上搜索(准则是:lib/pythonXX/os.py(os.pyc、os.pyo)文件)
Windows下,prefix和exec_prefix没多大意思了,主要就是确定Pyathon的主目录:
即 sys.path 的初始值:
如果使用 Py_SetPath() 设置了路径,则直接使用这些路径
再次:编译期设置的一些路径(通过宏PYTHONPATH),和prefix合并成得到的路径,比如:
于是,在linux下,可以见到:
'/usr/lib/python3.2' |
.py/.pyc/.pyo |
'/usr/lib/python3.2/plat-linux2' |
平台相关的 .py/.pyc/.pyo |
'/usr/lib/python3.2/lib-dynload' |
动态库的 .so |
http://docs.python.org/py3k/using/cmdline.html#envvar-PYTHONHOME
http://docs.python.org/py3k/c-api/init.html
http://docs.python.org/py3k/install/index.html