假设我有一个包含模块的包:
SWS/
__init.py__
foo.py
bar.py
time.py
并且模块需要引用彼此包含的功能。似乎我遇到了time.py
模块的问题,因为有一个标准模块同名。
例如,在我的foo.py
模块需要我的SWS.time
和标准python time
模块的情况下,我遇到了麻烦,因为解释器将查看包内并找到我的time.py
模块在遇到标准time
模块之前。
这有什么办法吗?这是禁止的情况吗?模块名称是否应该重复使用?
关于包装哲学的任何解决方案和意见在这里都很有用。
答案 0 :(得分:15)
重用标准函数/类/模块/包的名称绝不是一个好主意。尽量避免使用它。但是,您的情况有一些干净的解决方法。
您看到的导入SWS.time
而不是stdlib time
的行为是由于古代python版本(2.x)中import
的语义造成的。要修复它,请添加:
from __future__ import absolute_import
位于文件的最顶部。这会将import
的语义更改为python3.x的语义,这更加明智。在这种情况下声明:
import time
仅参考顶级模块。因此,在包中执行导入时,解释器将不考虑您的SWS.time
模块,但它只使用标准库。
如果您的包中的 模块需要导入SWS.time
,您可以选择:
使用显式相对导入:
from . import time
使用绝对导入:
import SWS.time as time
所以,你的foo.py
会是这样的:
from __future__ import absolute_import
import time
from . import time as SWS_time
答案 1 :(得分:8)
这取决于您使用的Python版本。如果您的目标Python版本是2.4或更早版本(在2015年,我当然希望不会),那么这是不好的做法,因为没有办法(没有黑客)来区分这两个模块。
但是,在Python 2.5+中,我认为在包命名空间中重用标准的lib模块名称非常好;事实上,那是the spirit of PEP328。
随着Python库的扩展,越来越多的现有软件包内部模块突然意外地影响了标准库模块。这是包装内部特别困难的问题,因为无法指定哪个模块是什么意思。为了解决这种歧义,建议foo始终是可以从sys.path访问的模块或包。这称为绝对导入。
python-dev社区选择绝对导入作为默认导入,因为它们是更常见的用例,因为绝对导入可以提供相对(包内)导入的所有功能 - 尽管代价是难度当在层次结构中更高的位置重命名包裹片段或将一个包裹移动到另一个包裹内时。
因为这代表了语义上的变化,所以通过使用
,绝对导入在Python 2.5和2.6中是可选的from __future__ import absolute_import
SWS.time
显然不与time
相同,作为代码的读者,我希望SWS.time
不仅仅使用{{1}但是以某种方式扩展它。
因此,如果time
需要导入SWS.foo
,那么它应该使用绝对路径:
SWS.time
或者,它应该使用显式相对导入,如Bakuriu的回答:
# in SWS.foo
# I would suggest renaming *within*
# modules that use SWS.time so that
# readers of your code aren't confused
# with which time module you're using
from SWS import time as sws_time
如果您需要在# in SWS.foo
from . import time as sws_time
模块中导入标准的lib time
模块,首先需要导入未来的功能(仅适用于Python 2.5+; Python 3+执行此操作默认情况下):
SWS.time
注意: # inside of SWS.time
from __future__ import absolute_import
import time
time.sleep(28800) # time for bed
只会影响导入未来功能的模块中的导入语句,并且不会影响任何其他模块(如果另一个模块依赖于相对进口,这将是有害的。)
答案 2 :(得分:5)
正如其他人所说,这通常是一个坏主意。
话虽如此,如果您正在寻找潜在的解决方法或更好地了解问题,我建议您阅读以下SO问题:
答案 3 :(得分:0)
是的,真的没有好办法解决它。尽量不要像标准包那样命名模块。如果您确实想要调用模块time
,我建议您使用_time.py
。即使有一种方法可以做到这一点,它也会使你的代码难以阅读并且在涉及2个时间模块时会引起混淆。