Python:导入子包或子模块

时间:2012-09-01 16:45:51

标签: python import module package

已经使用过扁平包,我没想到嵌套包遇到的问题。这是......

目录布局

dir
 |
 +-- test.py
 |
 +-- package
      |
      +-- __init__.py
      |
      +-- subpackage
           |
           +-- __init__.py
           |
           +-- module.py

init .py

的内容

package/__init__.pypackage/subpackage/__init__.py都是空的。

module.py

的内容
# file `package/subpackage/module.py`
attribute1 = "value 1"
attribute2 = "value 2"
attribute3 = "value 3"
# and as many more as you want...

test.py(3个版本)

的内容

版本1

# file test.py
from package.subpackage.module import *
print attribute1 # OK

这是导入东西的不良和不安全的方式(大量导入),但它确实有效。

第2版

# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
from module import attribute1

一种更安全的导入方式,逐项导入,但失败了,Python不希望这样:失败并显示消息:“没有模块命名模块”。然而...

# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
print module # Surprise here

...说<module 'package.subpackage.module' from '...'>。所以这是一个模块,但那不是模块/ -P 8-O ......呃

第3版

# file test.py v3
from package.subpackage.module import attribute1
print attribute1 # OK

这个有效。所以你要么被迫一直使用overkill前缀,要么使用版本#1中的不安全方式而Python不允许使用安全方便的方法?更好的方法是安全并避免不必要的长前缀是Python拒绝的唯一方法吗?这是因为它喜欢import *还是因为它喜欢过长的前缀(这无助于强制执行这种做法)?。

很抱歉这些难以理解的话,但是这两天我试图解决这种类似愚蠢的行为。除非我在某个地方完全错了,否则我会觉得Python的包和子包模型确实存在一些问题。

备注

  • 我不想依赖sys.path,以避免全局副作用,也不想依赖*.pth文件,这只是与sys.path玩全球效果相同的另一种方式。为了使解决方案清洁,它必须是本地的。要么Python能够处理子包,要么不是,但它不需要使用全局配置来处理本地的东西。
  • 我也尝试在package/subpackage/__init__.py中使用导入,但它没有解决任何问题,它也是如此,抱怨subpackage不是一个已知的模块,而print subpackage说它是一个模块(很奇怪)行为,再次)。

可能我完全错了(我更喜欢这个选项),但这让我对Python感到很失望。

除了我试过的三个之外还有其他任何已知的方法吗?我不知道的事情?

(叹气)

-----%&lt; -----编辑-----&gt;%-----

到目前为止的结论(在人们的评论之后)

Python中没有像真正的子包一样,因为所有包引用只转到全局词典,这意味着没有本地词典,这意味着无法管理本地包引用。

您必须使用完整前缀或短前缀或别名。如:

完整前缀版本

from package.subpackage.module import attribute1
# An repeat it again an again
# But after that, you can simply:
use_of (attribute1)

短前缀版本(但重复前缀)

from package.subpackage import module
# Short but then you have to do:
use_of (module.attribute1)
# and repeat the prefix at every use place

否则,是上述的变种。

from package.subpackage import module as m
use_of (m.attribute1)
# `m` is a shorter prefix, but you could as well
# define a more meaningful name after the context

分解版本

如果您不介意批量导入多个实体,您可以:

from package.subpackage.module import attribute1, attribute2
# and etc.

不是我最喜欢的口味(我更喜欢每个导入的实体都有一个导入语句),但可能是我个人喜欢的。

更新(2012-09-14):

最后在实践中似乎没问题,除了有关布局的评论。而不是上述,我用过:

from package.subpackage.module import (

    attribute1, 
    attribute2,
    attribute3,
    ...)  # and etc.

3 个答案:

答案 0 :(得分:51)

您似乎误解了import如何搜索模块。当您使用import语句时,始终搜索实际的模块路径(和/或sys.modules);由于以前的导入,它不会在本地命名空间中使用模块对象。当你这样做时:

import package.subpackage.module
from package.subpackage import module
from module import attribute1

第二行查找名为package.subpackage的包,并从该包中导入module。该行对第三行没有影响。第三行只是查找名为module的模块,但没有找到。它不会“重复使用”您从上面的行中获得的名为module的对象。

换句话说,from someModule import ...并不意味着“来自我之前导入的名为someModule的模块......”它意味着“来自在sys.path上找到的名为someModule的模块......”。没有办法通过导入导致它的包来“逐步”构建模块的路径。导入时总是需要引用整个模块名称。

目前尚不清楚你想要实现的目标。如果您只想导入特定对象attribute1,只需执行from package.subpackage.module import attribute1并完成它。一旦您从中导入了您想要的名称,就不必担心长package.subpackage.module

如果您 希望以后可以访问该模块以访问其他名称,那么您可以执行from package.subpackage import module,然后如您所见,您可以执行{{1}等你喜欢的等等。

如果你想要两者 ---也就是说,如果你想module.attribute1可以直接访问,你想要attribute1可以访问,那么上述内容:

module

如果您不喜欢键入from package.subpackage import module from package.subpackage.module import attribute1 attribute1 # works module.someOtherAttribute # also works 甚至两次,您只需手动创建对attribute1的本地引用:

package.subpackage

答案 1 :(得分:7)

#2失败的原因是因为sys.modules['module']不存在(导入例程有自己的范围,看不到module本地名称),并且没有{{1磁盘上的模块或包。请注意,您可以用逗号分隔多个导入的名称。

module

此外:

from package.subpackage.module import attribute1, attribute2, attribute3

答案 2 :(得分:0)

如果您要做的就是在全局命名空间中获取attribute1,那么版本3似乎没问题。为什么它是过度杀伤前缀?

在版本2中,而不是

from module import attribute1

你可以做到

attribute1 = module.attribute1