5

考虑一个这样的 Python 项目:

foo/
    __init__.py
scripts/
    run.py
demo.sh

foo在正常情况下,如果从项目的根目录运行脚本,尝试从包中导入会失败,因为默认的 Python 行为是将调用 Python 解释器的脚本目录 (不一定是当前目录)添加到sys.path. (文档):

python scripts/run.py

然而,我最近注意到这样的导入正在我的盒子上工作,我追踪到一些与 PYTHONPATH 相关的令人惊讶的行为。在我的 Bash 配置文件中,我向 PYTHONPATH 添加了一个目录:

export PYTHONPATH="/some/path:$PYTHONPATH"

如果 PYTHONPATH 最初为空,则该命令形式(有点草率,但很常见)将留下一个尾随冒号:

echo $PYTHONPATH
/some/path:

我一直认为这个尾随标点没有影响,但似乎尾随冒号是神秘成功导入的原因。前导或尾随冒号(甚至是已定义但为空的 PYTHONPATH)将导致在模块加载之前sys.path包含一个空字符串 ,这反过来又导致当前工作目录被添加到.sitesys.path

这里有一个 Python 脚本和一个 Bash 脚本来演示。我使用 Python 2.7 和 Python 3.3 得到了相同的行为。

Python脚本run.py::

import sys, os

pp = os.environ.get('PYTHONPATH')

try:
    import foo
    print 'OK'
    assert os.getcwd() in sys.path
    assert pp == '' or pp.startswith(':') or pp.endswith(':')

except Exception:
    print 'FAIL'
    assert os.getcwd() not in sys.path
    assert pp is None

bash 脚本demo.sh

# Import fails.
unset PYTHONPATH;  python scripts/run.py

# Import succeeds -- to my surprise.
PYTHONPATH=''      python scripts/run.py
PYTHONPATH='/tmp:' python scripts/run.py
PYTHONPATH=':/tmp' python scripts/run.py

我的问题

  • 我是否正确理解了情况,或者我是否误入歧途?

  • 这在任何地方都有记录吗?我什么也没找到。至少,我会在此处发布此信息,以防对其他人有所帮助。

  • 只有我一个人发现这种行为出乎意料吗?

4

1 回答 1

4

在修改以冒号分隔的环境变量(例如 PYTHONPATH、PATH、CPATH、MANPATH、LD_LIBRARY_PATH、PKG_CONFIG_PATH 等)时...其中一些变量对尾随冒号具有特殊意义,而另一些则没有。

对于 PYTHONPATH 和 PATH,如果变量之前未设置,我建议以不会意外引入尾随(或前导)冒号的方式预先(或附加)新目录:

export PYTHONPATH="/some/path${PYTHONPATH+":"}${PYTHONPATH-}"

(在 MANPATH 和 INFOPATH 的情况下,您确实man希望引入一个尾随冒号,以便info包含它们的默认搜索目录。)

解释:

  • ${PYTHONPATH+":"}如果 PYTHONPATH 已设置,则扩展为 a :,无论 PYTHONPATH 是否为空。
  • ${PYTHONPATH-}如果设置了 PYTHONPATH ,它将扩展为 PYTHONPATH 的内容,但如果未设置 PYTHONPATH ,则${PYTHONPATH-}扩展为空——就像通常的${PYTHONPATH}.

    • ${PYTHONPATH-}${PYTHONPATH-""}与未设置 PYTHONPATH 时替换“”(无)的含义相同。
    • ${PYTHONPATH-}${PYTHONPATH}这里推荐的原因是,${PYTHONPATH-}当 PYTHONPATH 未设置并且您的脚本已执行set -u以在未设置的变量上引发错误时,不会产生错误。

有关${parameter+[word]}和机制的详细信息,请参阅http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02${parameter-[word]}上的“参数扩展”

有关 的详细信息,请参见http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#setset -u中的“set”描述

于 2017-06-05T06:27:48.930 回答