想象一下这个目录结构:

app/
   __init__.py
   sub1/
      __init__.py
      mod1.py
   sub2/
      __init__.py
      mod2.py

我正在编码 mod1, ,我需要从中导入一些东西 mod2. 。我该怎么做呢?

我试过 from ..sub2 import mod2 但我收到“尝试在非包中进行相对导入”。

我用谷歌搜索但只发现“sys.path 操纵”黑客行为。难道就没有干净的办法吗?


编辑:我所有的 __init__.py目前是空的

编辑2:我试图这样做是因为 sub2 包含在子包之间共享的类(sub1, subX, , ETC。)。

编辑3:我正在寻找的行为与中描述的相同 公众号 366 (感谢约翰 B)

有帮助吗?

解决方案

每个人似乎都想告诉你应该做什么,而不仅仅是回答问题。

问题是您通过将 mod1.py 作为参数传递给解释器来将模块作为“__main__”运行。

PEP 328:

相对导入使用模块的 __name__ 属性来确定该模块在包层次结构中的位置。如果模块的名称不包含任何包信息(例如它被设置为“__main__”),然后解析相对导入,就像该模块是顶级模块一样,无论该模块实际位于文件系统上的位置。

在 Python 2.6 中,他们添加了相对于主模块引用模块的功能。 公众号 366 描述了变化。

更新:根据 Nick Coghlan 的说法,推荐的替代方案是使用 -m 开关运行包内的模块。

其他提示

main.py
setup.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       module_a.py
    package_b/ ->
       __init__.py
       module_b.py
  1. 你跑 python main.py.
  2. main.py 做: import app.package_a.module_a
  3. module_a.pyimport app.package_b.module_b

或者 2 或 3 可以使用: from app.package_a import module_a

只要你有,这就会起作用 app 在你的 PYTHONPATH 中。 main.py 那时可能在任何地方。

所以你写一个 setup.py 将整个应用程序包和子包复制(安装)到目标系统的 python 文件夹中,以及 main.py 目标系统的脚本文件夹。

这是适合我的解决方案:

我将相对导入作为 from ..sub2 import mod2然后,如果我想跑 mod1.py 然后我转到父目录 app 并使用 python -m 开关运行模块 python -m app.sub1.mod1.

相对导入出现此问题的真正原因是相对导入通过采用 __name__ 模块的属性。如果模块直接运行,那么 __name__ 被设定为 __main__ 并且它不包含任何有关包结构的信息。而且,这就是为什么 python 抱怨 relative import in non-package 错误。

因此,通过使用 -m 开关,您可以向 python 提供包结构信息,通过它可以成功解析相对导入。

我在做相对导入时多次遇到这个问题。而且,在阅读了之前的所有答案后,我仍然无法弄清楚如何以干净的方式解决它,而不需要在所有文件中放入样板代码。(尽管有些评论确实很有帮助,感谢@ncoghlan 和@XiongChiamiov)

希望这可以帮助那些正在与相对进口问题作斗争的人,因为经历 PEP 真的不好玩。

“Guido 将包内运行脚本视为反模式”(已拒绝PEP-3122)

我花了很多时间试图找到解决方案,阅读 Stack Overflow 上的相关帖子并对自己说“一定有更好的方法!”。好像没有。

这个问题已经100%解决了:

  • 应用程序/
    • 主要.py
  • 设置/
    • 本地设置.py

在app/main.py中导入settings/local_setting.py:

主要.py:

import sys
sys.path.insert(0, "../settings")


try:
    from local_settings import *
except ImportError:
    print('No Import')
def import_path(fullpath):
    """ 
    Import a file with full path specification. Allows one to
    import from anywhere, something __import__ does not do. 
    """
    path, filename = os.path.split(fullpath)
    filename, ext = os.path.splitext(filename)
    sys.path.append(path)
    module = __import__(filename)
    reload(module) # Might be out of date
    del sys.path[-1]
    return module

我正在使用此代码片段从路径导入模块,希望有帮助

的解释 nosklo's 举例回答

笔记:全部 __init__.py 文件为空。

main.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       fun_a.py
    package_b/ ->
       __init__.py
       fun_b.py

应用程序/package_a/fun_a.py

def print_a():
    print 'This is a function in dir package_a'

应用程序/package_b/fun_b.py

from app.package_a.fun_a import print_a
def print_b():
    print 'This is a function in dir package_b'
    print 'going to call a function in dir package_a'
    print '-'*30
    print_a()

主要.py

from app.package_b import fun_b
fun_b.print_b()

如果你跑 $ python main.py 它返回:

This is a function in dir package_b
going to call a function in dir package_a
------------------------------
This is a function in dir package_a
  • main.py 的作用是: from app.package_b import fun_b
  • fun_b.py 确实 from app.package_a.fun_a import print_a

文件夹中的so文件 package_b 文件夹中使用的文件 package_a, ,这就是你想要的。正确的??

不幸的是,这是一个 sys.path hack,但效果很好。

我在另一层遇到了这个问题:我已经有一个指定名称的模块,但它是错误的模块。

我想做的是以下(我正在使用的模块是 module3):

mymodule\
   __init__.py
   mymodule1\
      __init__.py
      mymodule1_1
   mymodule2\
      __init__.py
      mymodule2_1


import mymodule.mymodule1.mymodule1_1  

请注意,我已经安装了 mymodule,但在我的安装中没有“mymodule1”

我会收到一个 ImportError 错误,因为它试图从我安装的模块中导入。

我尝试执行 sys.path.append,但没有成功。所做的工作是 系统路径.插入

if __name__ == '__main__':
    sys.path.insert(0, '../..')

有点像黑客,但一切都正常了!所以请记住,如果您希望自己的决定 覆盖其他路径 那么你需要使用 sys.path.insert(0, pathname) 来让它工作!这对我来说是一个非常令人沮丧的症结所在,很多人说使用“append”函数到 sys.path,但如果你已经定义了一个模块,那么这不起作用(我发现这是非常奇怪的行为)

让我把这个放在这里供我自己参考。我知道这不是好的 Python 代码,但我需要一个用于我正在开发的项目的脚本,并且我想将该脚本放入 scripts 目录。

import os.path
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

正如 @EvgeniSergeev 在 OP 的评论中所说,您可以从 .py 文件在任意位置:

import imp

foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()

这是取自 这个答案.

看一眼 http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports. 。你可以做

from .mod1 import stuff

Python 文档,

在 Python 2.5 中,您可以使用以下命令将导入行为切换为绝对导入 from __future__ import absolute_import 指示。这种绝对导入行为将成为未来版本(可能是 Python 2.7)的默认行为。一旦绝对导入成为默认值, import string 总会找到标准库的版本。建议用户开始尽可能多地使用绝对导入,因此最好开始编写 from pkg import string 在你的代码中

我发现将“PYTHONPATH”环境变量设置到顶部文件夹更容易:

bash$ export PYTHONPATH=/PATH/TO/APP

然后:

import sub1.func1
#...more import

当然,PYTHONPATH是“全局的”,但它还没有给我带来麻烦。

除了约翰 B 所说的之外,似乎还设置了 __package__ 变量应该有帮助,而不是改变 __main__ 这可能会搞砸其他事情。但据我测试,它并没有完全按预期工作。

我有同样的问题,PEP 328 或 366 都不能完全解决问题,因为到一天结束时,两者都需要将包的头部包含在 sys.path, ,据我所知。

我还应该提到,我没有找到如何格式化应该进入这些变量的字符串。是吗 "package_head.subfolder.module_name" 或者是什么?

假设你在顶层运行,那么在 mod1 使用:

import sub2.mod2 

代替

from ..sub2 import mod2
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top