由于我已经使用了平面包,所以我没有料到会遇到嵌套包的问题。这是…
目录布局
dir
|
+-- test.py
|
+-- package
|
+-- __init__.py
|
+-- subpackage
|
+-- __init__.py
|
+-- module.py
初始化.py的内容
package/__init__.py
和package/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不希望这样:失败并显示消息:"No module named module“。然而,…
# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
print module # Surprise here
…<module 'package.subpackage.module' from '...'>
说。所以这是一个模块,但这不是一个模块。呃
版本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
的另一种方式,具有相同的全局效果。为了使解决方案是干净的,它必须仅是本地的。package/subpackage/__init__.py
中使用imports,但它什么也解决不了,它做了同样的事情,并抱怨subpackage
不是一个已知的模块,而print subpackage
说它是一个模块(行为也很奇怪)。也许我完全错了(这是我更喜欢的选择),但这让我对Python感到非常失望。
除了我试过的三种方法之外,还有其他已知的方法吗?有什么我不知道的吗?
(叹息)
- %< -编辑- >%
到目前为止(在人们的评论之后)
在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.
不是我最喜欢的(我更喜欢每个导入的实体有一个import语句),但可能是我个人喜欢的。
更新(2012-09-14):
最后在实践中看起来是可以的,除了关于布局的注释。我没有使用上面的代码,而是使用:
from package.subpackage.module import (
attribute1,
attribute2,
attribute3,
...) # and etc.
发布于 2012-09-02 01:09:37
您似乎误解了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
,正如您已经看到的,然后可以执行module.attribute1
,依此类推。
如果您想要这两者-也就是说,如果您想要直接访问attribute1
并且想要访问module
,只需执行上述两项操作:
from package.subpackage import module
from package.subpackage.module import attribute1
attribute1 # works
module.someOtherAttribute # also works
如果您不喜欢输入两次package.subpackage
,那么您可以手动创建一个对attribute1的本地引用:
from package.subpackage import module
attribute1 = module.attribute1
attribute1 # works
module.someOtherAttribute #also works
发布于 2012-09-02 00:50:34
2失败的原因是sys.modules['module']
不存在(导入例程有自己的作用域,并且看不到module
本地名称),并且磁盘上没有module
模块或包。请注意,您可以用逗号分隔多个导入的名称。
from package.subpackage.module import attribute1, attribute2, attribute3
另外:
from package.subpackage import module
print module.attribute1
发布于 2012-09-02 00:54:27
如果您所要做的只是将attribute1放入您的全局名称空间中,那么版本3看起来很不错。为什么它是overkill前缀?
在版本2中,而不是
from module import attribute1
你可以做到
attribute1 = module.attribute1
https://stackoverflow.com/questions/12229580
复制相似问题