首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Python:导入子包或子模块

Python:导入子包或子模块
EN

Stack Overflow用户
提问于 2012-09-02 00:45:51
回答 3查看 147.5K关注 0票数 113

由于我已经使用了平面包,所以我没有料到会遇到嵌套包的问题。这是…

目录布局

代码语言:javascript
复制
dir
 |
 +-- test.py
 |
 +-- package
      |
      +-- __init__.py
      |
      +-- subpackage
           |
           +-- __init__.py
           |
           +-- module.py

初始化.py的内容

package/__init__.pypackage/subpackage/__init__.py都为空。

module.py的内容

代码语言:javascript
复制
# 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

代码语言:javascript
复制
# file test.py
from package.subpackage.module import *
print attribute1 # OK

这是一种糟糕且不安全的导入方式(批量导入),但它是有效的。

版本2

代码语言:javascript
复制
# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
from module import attribute1

一种更安全的导入方法,逐项导入,但失败了,Python不希望这样:失败并显示消息:"No module named module“。然而,…

代码语言:javascript
复制
# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
print module # Surprise here

<module 'package.subpackage.module' from '...'>说。所以这是一个模块,但这不是一个模块。呃

版本3

代码语言:javascript
复制
# file test.py v3
from package.subpackage.module import attribute1
print attribute1 # OK

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

很抱歉说了这么多难听的话,但这两天我一直在努力解决这种愚蠢的行为。除非我在某处完全错了,否则这会让我感觉到Python的包和子包模型真的出了问题。

备注

  • 我不想依赖sys.path来避免全局副作用,也不想依赖*.pth文件,它们只是使用sys.path的另一种方式,具有相同的全局效果。为了使解决方案是干净的,它必须仅是本地的。
  • 我也尝试过在package/subpackage/__init__.py中使用imports,但它什么也解决不了,它做了同样的事情,并抱怨subpackage不是一个已知的模块,而print subpackage说它是一个模块(行为也很奇怪)。

也许我完全错了(这是我更喜欢的选择),但这让我对Python感到非常失望。

除了我试过的三种方法之外,还有其他已知的方法吗?有什么我不知道的吗?

(叹息)

- %< -编辑- >%

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

在Python中没有什么比得上真正的子包,因为所有的包引用都指向一个全局字典,这意味着没有本地字典,这意味着没有办法管理本地包引用。

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

完整前缀版本

代码语言:javascript
复制
from package.subpackage.module import attribute1
# An repeat it again an again
# But after that, you can simply:
use_of (attribute1)

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

代码语言:javascript
复制
from package.subpackage import module
# Short but then you have to do:
use_of (module.attribute1)
# and repeat the prefix at every use place

或者,上面的一种变体。

代码语言:javascript
复制
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

分解后的版本

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

代码语言:javascript
复制
from package.subpackage.module import attribute1, attribute2
# and etc.

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

更新(2012-09-14):

最后在实践中看起来是可以的,除了关于布局的注释。我没有使用上面的代码,而是使用:

代码语言:javascript
复制
from package.subpackage.module import (

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

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-09-02 01:09:37

您似乎误解了import搜索模块的方式。当您使用import语句时,它总是搜索实际的模块路径(和/或sys.modules);它不使用本地名称空间中的模块对象,这些模块对象是由于以前的导入而存在的。当你这样做的时候:

代码语言:javascript
复制
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,正如您已经看到的,然后可以执行module.attribute1,依此类推。

如果您想要这两者-也就是说,如果您想要直接访问attribute1并且想要访问module,只需执行上述两项操作:

代码语言:javascript
复制
from package.subpackage import module
from package.subpackage.module import attribute1
attribute1 # works
module.someOtherAttribute # also works

如果您不喜欢输入两次package.subpackage,那么您可以手动创建一个对attribute1的本地引用:

代码语言:javascript
复制
from package.subpackage import module
attribute1 = module.attribute1
attribute1 # works
module.someOtherAttribute #also works
票数 90
EN

Stack Overflow用户

发布于 2012-09-02 00:50:34

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

代码语言:javascript
复制
from package.subpackage.module import attribute1, attribute2, attribute3

另外:

代码语言:javascript
复制
from package.subpackage import module
print module.attribute1
票数 11
EN

Stack Overflow用户

发布于 2012-09-02 00:54:27

如果您所要做的只是将attribute1放入您的全局名称空间中,那么版本3看起来很不错。为什么它是overkill前缀?

在版本2中,而不是

代码语言:javascript
复制
from module import attribute1

你可以做到

代码语言:javascript
复制
attribute1 = module.attribute1
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12229580

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档