19

假设我有一个包含模块的包:

SWS/
  __init.py__
  foo.py
  bar.py
  time.py

并且模块需要引用彼此中包含的功能。似乎我的time.py模块遇到了问题,因为有一个同名的标准模块。

例如,如果我的foo.py模块同时需要我SWS.time的和标准的 pythontime 模块,我就会遇到麻烦,因为解释器会在包内部查找并time.py在遇到标准模块之前找到我的time模块。

有没有办法解决?这是禁止的情况吗?不应该重用模块名称吗?

任何关于包装哲学的解决方案和意见在这里都会很有用。

4

4 回答 4

18

重用标准函数/类/模块/包的名称绝不是一个好主意。尽量避免它。但是,您的情况有一些干净的解决方法。

您看到的行为是导入 yourSWS.time而不是 stdlib time,这是由于import古代 python 版本(2.x)中的语义。要修复它,请添加:

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
于 2015-03-04T12:14:05.597 回答
10

这取决于您使用的 Python 版本。如果您的目标 Python 版本是 2.4 或更早版本(2015 年,我当然希望不是),那么是的,这将是不好的做法,因为没有办法(没有黑客)来区分这两个模块。

但是,在 Python 2.5+ 中,我认为在包命名空间中重用标准 lib 模块名称是非常好的;其实这就是PEP328的精神

随着 Python 库的扩展,越来越多的现有包内部模块突然意外地隐藏了标准库模块。这是包内部的一个特别困难的问题,因为无法指定哪个模块是指的。为了解决歧义,建议 foo 始终是可从 sys.path 访问的模块或包。这称为绝对导入。

python-dev 社区选择绝对导入作为默认值,因为它们是更常见的用例,并且因为绝对导入可以提供相对(包内)导入的所有功能——尽管在重命名包块时会以困难为代价在层次结构中向上或在将一个包移动到另一个包时。

因为这代表了语义的变化,所以绝对导入在 Python 2.5 和 2.6 中是可选的,通过使用from __future__ import absolute_import

SWS.time显然与代码的读者不同,我希望不仅使用,而且以某种方式扩展它。timeSWS.timetime

所以,如果SWS.foo需要 import SWS.time,那么它应该使用绝对路径:

# 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

或者,它应该使用Bakuriu 的回答中的显式相对导入:

# in SWS.foo

from . import time as sws_time

如果您需要在模块中导入标准 libtime模块SWS.time,您首先需要导入未来的功能(仅适用于 Python 2.5+;Python 3+ 默认情况下会这样做):

# inside of SWS.time
from __future__ import absolute_import

import time

time.sleep(28800)  # time for bed

注意: from __future__ import absolute_imports只会影响导入未来功能的模块中的导入语句,不会影响任何其他模块(因为如果另一个模块依赖于相对导入,那将是有害的)。

于 2015-11-01T15:54:23.250 回答
5

正如其他人所说,这通常是一个坏主意。

话虽如此,如果您正在寻找潜在的解决方法,或者更好地理解问题,我建议您阅读以下 SO 问题:

于 2012-05-08T15:24:49.893 回答
0

是的,确实没有什么好办法。尽量不要将你的模块命名为标准包。如果您真的想调用您的模块time,我建议您_time.py改用。即使有办法做到这一点,当涉及到 2 个时间模块时,它也会使您的代码难以阅读和混淆。

于 2012-05-08T15:19:55.810 回答