2010-09-01 70 views
26

使用有一个缺点,你将无法运行模块,standalones了,因为你会得到一个异常:ValueError: Attempted relative import in non-package如何在Python模块中正确使用相对或绝对导入?在Python相对进口

# /test.py: just a sample file importing foo module 
import foo 
... 

# /foo/foo.py: 
from . import bar 
... 
if __name__ == "__main__": 
    pass 

# /foo/bar.py: a submodule of foo, used by foo.py 
from . import foo 
... 
if __name__ == "__main__": 
    pass 

我应该如何修改示例代码为了能够执行所有:test.py,foo.pybar.py

我正在寻找一种可以与python 2.6+(包括3.x)一起使用的解决方案。

+1

检查此主题:http://www.velocityreviews.com/forums/t502905-relative-import-broken.html – 2010-09-01 10:41:02

+0

谢谢,不幸的是我知道这个老线程,但我发现没有解决问题。到目前为止,我只观察到很多人抱怨这一点。我们需要一个清晰的解决方案/例子解决这个问题 – sorin 2010-09-01 11:57:17

+0

相关:[如何知道python脚本是否使用解释器的-m选项运行?](http://stackoverflow.com/questions/8348726/) – 2011-12-01 23:28:54

回答

16

首先,我假设你意识到你写的会导致循环导入问题,因为foo导入bar和viceversa;尝试添加

from foo import bar 

to test.py,并且您将看到它失败。该示例必须更改才能工作。

所以,你要求的是当相对导入失败时真正回退到绝对导入;实际上,如果你正在执行foo.py或bar.py作为主模块,那么其他模块就会位于根级别,如果它们与系统中的另一个模块共享该名称,则取决于sys.path中的顺序。由于当前目录通常是第一个,因此如果可用,将选取本地模块 - 即,如果在当前工作目录中有一个“os.py”文件,它将被选中而不是内置文件。

一个可能的建议是:

foo。PY

try: 
    from . import bar 
except ValueError: 
    import bar 

if __name__ == "__main__": 
    pass 

bar.py:

if __name__ == "__main__": 
    pass 

通过从适当位置调用脚本的方式通常是方式更好。

python -m foo.bar 

可能是最好的选择。这runs the module as a script

+0

我不认为'except'语句中的'import bar'可以用于Python 3.1+ – John 2013-04-06 22:42:46

+0

@John,据我所知,没有任何理由,因为在except语句中导入不应该起作用。它在Python 3.2中工作100%。 – 2014-04-17 14:35:02

-2

到目前为止,我发现的唯一解决方案是根本不使用相对导入。

由于目前的限制,我想知道什么时候有人应该在Python中使用相对导入。

在我使用sys.path包含当前目录作为第一个参数的所有配置中,只需使用import foo而不是from . import foo,因为它会执行相同的操作。

+3

但是,当您决定使用与您的软件包中的模块名称相同的python标准或第三方模块时,会造成问题。这就是为什么恕我直言,使用'from __future__ import absolute_import'和相对导入好得多。 – 2010-09-01 12:18:42

22

你可能只是开始有点 '运行模块,standalones' 以不同的方式:

相反的:

python foo/bar.py 

用途:

python -mfoo.bar 

当然, foo/__init__.py文件必须存在。

请注意,你有一个循环依赖foo.pybar.py - 这是行不通的。我想这在你的例子中只是一个错误。

更新:它似乎也工作得很好利用这个作为foo/bar.py的第一行:

#!/usr/bin/python -mfoo.bar 

然后你就可以在POSIX系统直接执行脚本。

+3

这是一个丑陋的黑客,我认为这是不可接受的,特别是因为它更难执行它们(特别是在Windows上) – sorin 2010-09-01 12:39:44

+0

顺便说一句,即使是循环导入,bogdan的例子也能工作。 – sorin 2010-09-01 12:42:28

+15

+1,这是将“独立执行”模块**作为包**的一部分的正确方法**(当然,如果您想使用相对导入,则必须这样做)。 – 2010-09-04 04:53:57

0

为什么不把“主”放在另一个.py文件中?

1

沟渠相关导入:无论如何,您应该将您的软件包命名空间视为全局命名空间。

使这个可口的诀窍是适当地编辑sys.path。这里有一些想法:

 
# one directory up 
_root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) 
sys.path.insert(0, _root_dir)for now 
+4

-1。不要丢弃相对的进口;当绝对导入功能被设计为http://mail.python.org/pipermail/python-dev/2003-December/041065.html时,他们被认为是很好的,他们今天也一样好。 – bignose 2012-09-09 04:51:03

1

你需要在每个文件夹__init__.py

相对进口只能当你这样做:

python test.py 

test.py进口foo.py改为和foo.py可以相对从test.py及以上的文件夹,输入任何东西。

你不能做:

cd foo 
python foo.py 
python bar.py 

它永远不会工作。

你可以尝试sys.path.append或sys.path.insert解决方案,但你会搞砸路径,你会遇到f = open(filename)的问题。