好的,所以我真的想要做到这一点,因为我在生成一些大的py2app / py2exe包时会继续遇到它。所以我的包中包含很多模块/包,这些模块/包也可能在用户站点包/默认位置(如果用户有python发行版)但我希望我的分布式包在从我的发行版运行时生效。
现在从我读过here PYTHONPATH 应该是当前目录之后添加到sys.path的第一件事,但是我在我的机器上测试的是不是这种情况,$site-packages$/easy-install.pth
中定义的所有文件夹都优先于此。
有人可以请给我一些关于这个导入顺序的更深入的解释//帮我找到一种方法来设置环境变量,使我分发的包优先于默认安装的包。到目前为止,我的尝试是,例如在Mac-OS py2app上,在我的入口点脚本中:
os.environ['PYTHONPATH'] = DATA_PATH + ':'
os.environ['PYTHONPATH'] = os.environ['PYTHONPATH'] + os.path.join(DATA_PATH
, 'lib') + ':'
os.environ['PYTHONPATH'] = os.environ['PYTHONPATH'] + os.path.join(
DATA_PATH, 'lib', 'python2.7', 'site-packages') + ':'
os.environ['PYTHONPATH'] = os.environ['PYTHONPATH'] + os.path.join(
DATA_PATH, 'lib', 'python2.7', 'site-packages.zip')
这基本上是py2app生成的包的结构。然后我就是:
SERVER = subprocess.Popen([PYTHON_EXE_PATH, '-m', 'bin.rpserver'
, cfg.RPC_SERVER_IP, cfg.RPC_SERVER_PORT],
shell=False, stdin=IN_FILE, stdout=OUT_FILE,
stderr=ERR_FILE)
这里PYTHON_EXE_PATH是python应用程序添加到包中的python exe的路径。现在,这在没有安装python的机器上运行良好。但是,当python发布已经存在时,它们的站点包优先。
答案 0 :(得分:16)
Python按顺序搜索sys.path
中的路径(请参阅http://docs.python.org/tutorial/modules.html#the-module-search-path)。 easy_install直接更改此列表(请参阅easy-install.pth文件中的最后一行):
import sys; new=sys.path[sys.__plen:]; del sys.path[sys.__plen:]; p=getattr(sys,'__egginsert',0); sys.path[p:p]=new; sys.__egginsert = p+len(new)
这基本上取了添加的任何目录,并将它们插入列表的开头。
答案 1 :(得分:0)
导入模块后,python首先从sys.modules
目录列表中搜索。
如果找不到,则从sys.path
目录列表中搜索。在您的操作系统上可能还有其他python搜索列表
import time , sys
print (sys.modules)
print (sys.path)
输出是目录列表:
{... , ... , .....}
['C:\\Users\\****', 'C:\\****', ....']
time
模块是按照sys.modules
和sys.path
列表的顺序导入的。
答案 2 :(得分:0)
即使以上关于口译员扫描sys.path
的顺序的答案是正确的,也优先考虑例如如果site-packages
变量中没有完整的用户路径,则通过PYTHONPATH
部署的软件包的用户文件路径可能会失败。
例如,假设您具有以下名称空间包结构:
/opt/repo_root
- project # this is the base package that brigns structure to the namespace hierarchy
- my_pkg
- my_pkg-core
- my_pkg-gui
- my_pkg-helpers
- my_pkg-helpers-time_sync
以上软件包都具有内部所需的结构和元数据,以便可以通过conda进行部署,并且这些软件包也都已安装。因此,我可以打开python shell并键入:
>>> from project.my_pkg.helpers import time_sync
>>> print(time_sync.__file__)
/python/interpreter/path/lib/python3.6/site_packages/project/my_pkg/helpers/time_sync/__init__.py
将在python解释器的site-packages
子文件夹中返回一些路径。如果我手动将要导入的软件包添加到PYTHONPATH
或什至sys.path
,则什么都不会改变。
>>> import os
>>> # joining separator ":" for Unix, ";" for NT
>>> os.environ['PYTHONPATH'] = ":".join(os.environ['PYTHONPATH'], "/opt/repo_root/my_pkg-helpers-time_sync")
>>> from project.my_pkg.helpers import time_sync
>>> print(time_sync.__file__)
/python/interpreter/path/lib/python3.6/site_packages/project/my_pkg/helpers/time_sync/__init__.py
仍然返回该软件包已从site-packages
导入。您需要将路径的整个层次结构都包含在PYTHONPATH
中,就像它是传统的python软件包一样,然后它才能按预期工作:
>>> import os
>>> # joining separator ":" for Unix, ";" for NT
>>> os.environ['PYTHONPATH'] = ":".join(
... os.environ['PYTHONPATH'],
... "/opt/repo_root",
... "/opt/repo_root/project",
... "/opt/repo_root/project/my_pkg",
... "/opt/repo_root/project/my_pkg-helpers",
... "/opt/repo_root/project/my_pkg-helpers-time_sync"
... )
>>> from project.my_pkg.helpers import time_sync
>>> print(time_sync.__file__)
/opt/project/my_pkg/helpers/time_sync/__init__.py
答案 3 :(得分:-1)
此页面是Google对“ Python导入顺序”的最高评价,因此,这里的解释希望会更清楚:
这两个页面都说明,import
的顺序是:
sys.path
项。并且如sys.path
文档页面所述,其填充如下:
python
开头的文件的完整路径(因此/someplace/on/disk/> $ python /path/to/the/run.py
表示第一个路径为/path/to/the/
,如果您位于/path/to/> $ python the/run.py
(仍将始终设置为目录的FULL PATH),或者如果python是在没有文件aka交互模式的情况下启动的,则它将是一个空字符串(空字符串表示“当前工作目录”用于python进程”)。换句话说,Python假设您启动的文件希望能够相对导入与您启动python的文件位于同一位置的package/-folders
和blah.py
模块。sys.path
环境变量中填充了PYTHONPATH
中的其他条目。基本上是您的全局pip文件夹。因此,基本上:是的,您可以放心,Python会在任何全局安装的pip东西之前先找到本地的软件包文件夹和模块文件。
下面是一个进一步解释的示例:
myproject/ # <-- This is not a package (no __init__.py file).
modules/ # <-- This is a package (has an __init__.py file).
__init__.py
foo.py
run.py
second.py
executed with: python /path/to/the/run.py
will cause sys.path[0] to be "/path/to/the/"
run.py contents:
import modules.foo as foo # will import "/path/to/the/" + "modules/foo.py"
import second # will import "/path/to/the/" + "second.py"
second.py contents:
import modules.foo as foo # will import "/path/to/the/" + "modules/foo.py"