【问题标题】:Why does PYTHONPATH with trailing colon add current directory to sys.path?为什么带有尾随冒号的 PYTHONPATH 将当前目录添加到 sys.path?
【发布时间】:2015-11-09 17:54:12
【问题描述】:

考虑一个这样的 Python 项目:

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

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

python scripts/run.py

但是,我最近注意到此类导入正在我的盒子上工作,我 将其归结为与 PYTHONPATH 相关的一些令人惊讶的行为。在我的 Bash profile 我已经向 PYTHONPATH 添加了一个目录:

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

如果 PYTHONPATH 最初是空的,那(有点草率,但很常见) 命令的形式会留下一个尾随冒号:

echo $PYTHONPATH
/some/path:

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

我的问题:

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

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

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

【问题讨论】:

  • 无法在 Windows 上复制。
  • 您对正在发生的事情是正确的,我发现这种行为出乎意料且不受欢迎。向 python 恕我直言报告错误是值得的,除了像这样长期存在的怪事在修复后会破坏事情。
  • 或者我收回它。 export "PATH=$PATH:" lets 本地路径中的命令在 linux 上执行。 Python 的工作方式相同。
  • @tdelaney 谢谢——这是一个很好的测试。我想 Python 的行为根据 Unix 的行为是有意义的……但它们似乎都违反直觉。也许这里有很深的逻辑。
  • 是的 - 只是重复了你的发现,然后谷歌搜索“python路径尾随冒号”并偶然发现了你的答案。至少可以说似乎次优。

标签: python import pythonpath sys.path


【解决方案1】:

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

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

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

(对于 MANPATH 和 INFOPATH,您确实想要引入尾随冒号,以便 man 和 info 包含它们的默认搜索目录。)

解释:

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

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

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

set -u详情见http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set“设置”说明

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-13
    • 1970-01-01
    • 1970-01-01
    • 2011-03-25
    • 1970-01-01
    • 2015-12-18
    相关资源
    最近更新 更多