【问题标题】:Python code runs from IDE, but not from terminalPython 代码从 IDE 运行,但不是从终端运行
【发布时间】:2018-07-09 23:18:11
【问题描述】:

当我尝试从 Linux 终端运行代码时,我的导入不起作用。具体来说,从同一项目中的其他包导入。我知道这是一个 PYTHONPATH 问题,但我不知道如何进一步诊断或解决它。 代码在 IDE (eclipse) 中运行良好。

我对永久解决方案感兴趣,猜测它会涉及编辑 .bashrc。我只是想从命令行调用脚本,比如

python my_script.py

os.environ["PYTHONPATH"] 在 ipython 终端中出现关键错误。

我试过了

print os.getcwd()
print sys.path

IDE 内部

/home/myname/workspace/project2/main

['/home/myname/workspace/project2/main', '/home/myname/workspacep/problem2', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_6
4-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/p
ython2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PILcompat', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/pytho
n2.7/dist-packages/ubuntu-sso-client', '/usr/lib/pymodules/python2.7', '/usr/lib/python2.7/lib-old']

内部终端

/home/myname/workspace/project2/main

['/home/myname/workspace/project2/main', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_64-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PILcompat', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/python2.7/dist-packages/ubuntu-sso-client']

【问题讨论】:

  • 这很可能是由于您在不同的路径上执行了脚本。尝试有一个打印os.getcwd()sys.path 的脚本,然后在您的IDE 和您正在执行脚本的同一位置上单独运行它。你会看到不同。您可以尝试sys.path.append() IDE 的os.getcwd() 的绝对路径。
  • 我根据您的指示添加了详细信息。什么是永久解决方案,你能告诉我一步一步吗?我不知道 sys.path.append() 到底是什么意思,我怀疑这是一个永久的解决方案。我希望能够使用 python my_script.py 从命令行调用 python 脚本
  • IMO 的永久解决方案是将您的模块转换为一个包并使用您的 pip 安装它,这将确保您的代码在安装包后可以在任何计算机上的任何路径上运行。但这是必要的更多工作。下一个最佳解决方案是 @JohnH 添加到 PATH 环境的答案,您可以阅读更多 hereappend() 是一个临时解决方案,但取决于您的项目大小,这可能就是您所需要的。

标签: python python-import pythonpath


【解决方案1】:

Pycharm Eclipse 和 bash shell 中执行脚本的区别在于环境变量 $PYTHONPATH 的值。

Pycharm 中,转到首选项,然后项目解释器设置并将鼠标悬停在您在终端中找不到的包上。该包所在的路径应该会显示出来。 Eclipse,找出你的项目的环境变量存储在哪里,或者找到有问题的模块的路径。

使用

将该路径添加到 shell 中的 $PYTHONPATH
PYTHONPATH=$PYTHONPATH:your/path/here

您可以将该行添加到您的 .bashrc 或 .bash_profile 文件中,您可以将其添加到您的 bash 脚本中,或者您可以每次都键入它。

更新以响应 OP 评论:

使用指向您未找到的 python 模块的安装目录的路径。

试试

python -v

在您的 IDE 控制台中。这应该会给你一个模块列表和它们的目录。

在你的 shell 中使用相同的命令,不同之处会告诉你缺少什么。

【讨论】:

  • 我用的是eclipse,不是Pycharm。
  • 那么我用什么代替你的/path/here, /home/myname/workspace/ 呢?基于原始问题中的示例。
【解决方案2】:

如前所述,为了说明 IDE 执行和终端执行期间使用的路径的区别,请在 IDE 和终端中运行以下脚本:

import os
import sys
print(os.getcwd())
for i in sys.path:
    print(i)

比较您的结果,当从终端执行时,与在 IDE 中运行相比,这些文件夹丢失了:

'/home/myname/workspacep/problem2' 
'/usr/lib/pymodules/python2.7'

需要注意的是,当前工作目录和sys.paths 在终端中更改,具体取决于您从哪里运行它以及文件所在的位置。但关键是sys.paths,因为它们告诉 python 在哪里寻找模块。

我敢打赌,您尝试导入的模块来自这些文件夹之一,很可能位于 /home/myname/workspacep/problem2 下。这会带来一些问题,因为您的模块既没有存储在集中访问位置(例如,/usr/lib/python2.7/my_modules),也没有存储在项目结构下的子文件夹中。

为了说明,我有一个模拟项目文件夹设置如下:

pi@box:~/project $ tree
.
├── main.py
├── mod1.py
└── subfolder
    ├── __init__.py
    ├── main.py
    └── mod2.py

在子文件夹see here for more details 下有一个空的__init__.py 是个好主意。我的main.py 看起来像这样:

import os
import sys

print(f'cwd = {os.getcwd()}')
print(f'path0 = {sys.path[0]}')

try:
    import mod1
    mod1.hello()
except Exception as e:
    print(f'import mod1 failed: {e}')

try:
    from subfolder import mod2
    mod2.hello()
except Exception as e:
    print(f'from subfolder import mod2 failed: {e}')

try:
    import mod2 as mod2copy
    mod2copy.hello()
except Exception as e:
    print(f'import mod2copy failed: {e}')

下面是我在终端中尝试在projectproject/subfolder下运行main.py时的执行结果:

pi@box:~/project $ python3 main.py

cwd = /home/pi/project
path0 = /home/pi/project
Module 1 reporting in!
Module 2 reporting in!
import mod2copy failed: No module named 'mod2'

pi@box:~/project $ python3 ./subfolder/main.py

cwd = /home/pi/project
path0 = /home/pi/project/subfolder
import mod1 failed: No module named 'mod1'
from subfolder import mod2 failed: No module named 'subfolder'
Module 2 reporting in!

pi@box:~/project $ cd subfolder
pi@box:~/project/subfolder $ python3 main.py

cwd = /home/pi/project/subfolder
path0 = /home/pi/project/subfolder
import mod1 failed: No module named 'mod1'
from subfolder import mod2 failed: No module named 'subfolder'
Module 2 reporting in!

pi@box:~/project/subfolder $ python3 ../main.py

cwd = /home/pi/project/subfolder
path0 = /home/pi/project
Module 1 reporting in!
Module 2 reporting in!
import mod2copy failed: No module named 'mod2'

可以看到,在cwdsys.path之间,直接影响我的imports的是sys.path,这取决于你的main.py的存储位置。在项目根目录下运行main.py 时,我能够按预期从根目录导入mod1 和从子文件夹导入mod2mod2copy 应该失败,因为根目录中没有 mod2。但是在执行存储在子文件夹中的main.py 时,mod1 无法导入,因为 python 不知道 mod1 的存储位置,因为缺少 sys.path。但是,如果我在importing 之前添加以下行:

sys.path.append('/home/pi/project')

子文件夹下main.py的结果会变成:

pi@rpirpirpi:~/project/subfolder $ python3 main.py

cwd = /home/pi/project/subfolder
path0 = /home/pi/project/subfolder
Module 1 reporting in!
Module 2 reporting in!
Module 2 reporting in!

您会注意到所有 3 个导入都成功。 Python 能够找到mod1/subfolder/mod2,因为根路径现在已添加到脚本的sys.path。并且mod2copy 仍然成功,因为subfolder 在追加之前已经是sys.path 列表的一部分。

话虽如此,当您有一个模块引用子结构中的另一个模块时,它会变得混乱。假设/subfolder/module3 尝试import mod2,而您正在从/project/main.py 执行,当您的脚本执行from subfolder import mod3 时,import mod2 行将像以前一样返回ModuleNotFoundError,因为sys.path 不包含@ 987654367@,因此您需要在模块之间的所有这些imports 中使用一些技巧。要考虑的另一件事是相对路径 - 如果您开始移动文件,所有这些 sys.path 都需要维护。

总而言之 - 如果您希望导入既不在 Python 库中也不嵌套在项目根目录下的模块,那么您的日子就不好过了。

对于小型临时项目(例如,在完成模块之前的临时测试),上述方法是一种快速简便的补救措施。但是,如果您打算在未来的项目中重用这些模块,请考虑将它们存储在集中路径中并添加到您的 PYTHONPATH。 This thread have some more information,,例如如果你想将你的模块存储在/home/myname/modules下:

将以下行添加到您的~/.bashrc

export PYTHONPATH="${PYTHONPATH}:/home/myname/modules"

...然后在modules(包括modules本身)下创建的每个文件夹中添加一个名为__init__.py的空文件以避免导入问题。

如前所述,如果您准备好进行额外的工作,您可以随时考虑将模块转换为一个包并通过 pip 安装它。这样你就完全不用担心 PATH 的处理了。

【讨论】:

  • 那么在您的示例中,我可以使用什么来代替 /home/myname/modules?它是工作区的路径,还是我需要自己做项目,就像在 project2 中一样?我不想为每个项目单独做这件事,如果我能侥幸的话。
  • 如果您愿意,可以将路径 /home/myname/workspace/problem2 添加到您的 PYTHONPATH,但是问题 3 会发生什么?问题4?你最终会得到一堆 PYTHONPATH 污染你的环境。因此,为什么如果它是临时的,我会正确设置文件夹结构,或者如果失败,请使用sys.path.append。否则,您可以做的最好的事情是按照建议在主文件夹下构建您的模块。没有简单的解决方案,根本原因在于项目结构。
【解决方案3】:

终端执行与 IDE 执行之间存在差异的原因可能是虚拟环境可能是为 IDE 配置的,而不是为您通过终端运行代码的实际环境配置的。 您可以通过运行命令来检查它:path_of_virt_env your_command。 'path_of_virt_env' 是 IDE 在运行代码表单 IDE 时在控制台上显示为输出的第一个参数。 现在,要解决这个问题,请在终端中安装所有导入的库。

【讨论】:

    【解决方案4】:

    我的问题是我正在使用的 python 文件的名称,它与我正在导入的包的名称相同并做了一个循环

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-19
      • 2021-09-12
      • 1970-01-01
      • 1970-01-01
      • 2013-04-14
      • 2012-09-04
      • 2014-12-20
      相关资源
      最近更新 更多