python路径和导入顺序

Bog*_*dan 19 python

好的,所以我真的想要做到这一点,因为我在生成一些大的py2app/py2exe包时会继续遇到它.所以我的包中包含很多模块/包,这些模块/包也可能在用户站点包/默认位置(如果用户有python发行版)但我希望我的分布式包在从我的发行版运行时生效.

现在从我在这里 读到的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')
Run Code Online (Sandbox Code Playgroud)

这基本上是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)
Run Code Online (Sandbox Code Playgroud)

这里PYTHON_EXE_PATH是由py2app添加到包的python exe的路径.现在,这在没有安装python的机器上运行良好.但是,当python发布已经存在时,它们的站点包优先.

cwa*_*cwa 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)
Run Code Online (Sandbox Code Playgroud)

这基本上取了添加的任何目录,并将它们插入列表的开头.

另请参阅PYTHONPATH环境变量之前的路径中的Eggs.


Mit*_*ers 7

这个页面是“Python 导入顺序”的高谷歌搜索结果,所以这里有一个希望更清晰的解释:

正如这两页所解释的,import顺序是:

  1. 内置python模块。您可以在变量中看到列表sys.modules
  2. sys.path条目。
  3. 依赖于安装的默认位置。

正如sys.path文档页面所解释的,它的填充如下:

  1. 第一项是完整路径的文件的目录python启动时使用(所以/someplace/on/disk/> $ python /path/to/the/run.py意味着第一条路径是/path/to/the/,同样,如果你所在的路径将是相同的/path/to/> $ python the/run.py(它仍然总是会被设置为FULL PATH 到目录,无论你给 python 一个相对文件还是绝对文件)),或者如果 python 在没有文件即交互模式的情况下启动,它将是一个空字符串(空字符串表示“python进程的当前工作目录”) . 换句话说,Python 假设您启动的文件希望能够对package/-foldersblah.py启动 Python 的文件位于同一位置的模块进行相对导入。
  2. 中的其他条目sys.pathPYTHONPATH环境变量填充。基本上是安装了第三方 python 包的全局 pip 文件夹(例如requestsandnumpytensorflow)。

所以,基本上:是的,你可以相信 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/myproject/run.py
will cause sys.path[0] to be "/path/to/the/myproject/"

run.py contents:
import modules.foo as foo # will import "/path/to/the/myproject/" + "modules/foo.py"
import second # will import "/path/to/the/myproject/" + "second.py"

second.py contents:
import modules.foo as foo # will import "/path/to/the/myproject/" + "modules/foo.py"
Run Code Online (Sandbox Code Playgroud)

编辑:

您可以运行以下命令来打印所有内置模块名称的排序列表。这些是在项目中的任何自定义文件/模块文件夹之前加载的内容。基本上,这些是您在自己的自定义文件中必须避免的名称:

python -c "import sys, json; print(json.dumps(sorted(list(sys.modules.keys())), indent=4))"

从 Python 3.9.0 开始列出:

"__main__",
"_abc",
"_bootlocale",
"_codecs",
"_collections",
"_collections_abc",
"_frozen_importlib",
"_frozen_importlib_external",
"_functools",
"_heapq",
"_imp",
"_io",
"_json",
"_locale",
"_operator",
"_signal",
"_sitebuiltins",
"_sre",
"_stat",
"_thread",
"_warnings",
"_weakref",
"abc",
"builtins",
"codecs",
"collections",
"copyreg",
"encodings",
"encodings.aliases",
"encodings.cp1252",
"encodings.latin_1",
"encodings.utf_8",
"enum",
"functools",
"genericpath",
"heapq",
"io",
"itertools",
"json",
"json.decoder",
"json.encoder",
"json.scanner",
"keyword",
"marshal",
"nt",
"ntpath",
"operator",
"os",
"os.path",
"pywin32_bootstrap",
"re",
"reprlib",
"site",
"sre_compile",
"sre_constants",
"sre_parse",
"stat",
"sys",
"time",
"types",
"winreg",
"zipimport"
Run Code Online (Sandbox Code Playgroud)

所以永远不要对你的.py文件或你的项目模块子文件夹使用任何这些名称。