2012-05-08 72 views
9

假设我有一个包含模块的程序包:Python模块具有相同名称(即,在包中重新使用标准模块名称)

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

和模块需要参考包含在彼此的功能。看起来我遇到了与我的time.py模块有关的问题,因为有一个标准模块出现相同的名称。

举例来说,在我的foo.py模块既需要我SWS.time和标准Python time模块的情况下,我遇到了麻烦,因为解释器会看包里面找到我time.py模块它遇到的标准time模块之前。

有没有解决这个办法吗?这是否是否定的情况,模块名称是否应该重用?

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

+2

我认为这很明显,你不应该重用标准的python模块名称。这只是要求麻烦。 – Cryptite

+3

为什么显而易见? MikeWyatt

+0

查看httplib/httplib2和urllib/urllib2。它造成了一个丑陋的图书馆世界,但这更适合于命名冲突和不确定的行为。 –

回答

10

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

您看到的行为,导入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 
+2

我认为,当模块名称存在名称空间*时,这不是一个坏主意*,就像一个包一样。这是PEP328的精神。请参阅下面的答案。 – OozeMeister

0

是的,真的没有什么好方法。尽量不要将模块命名为标准包。如果你真的想打电话给你的模块time,我建议使用_time.py来代替。即使有办法做到这一点,它会让你的代码在2个时间模块中难以阅读和混淆。

4

这取决于你所使用的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不仅使用time,但以某种方式扩展它。

所以,如果SWS.foo需要导入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 

如果您需要导入SWS.time模块中的标准库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只会影响import语句未来功能导入模块,将不会影响任何其他模块(因为这将如果另一个模块依赖于相对导入,则是有害的)。

+0

请注意,您的PEP 8引用**已过时**。当前版本的PEP 8 *支持使用相对导入*:quote:*明确的相对导入是绝对导入的可接受替代方案,特别是在处理复杂的包装布局时,使用绝对导入会导致不必要的冗长* – Bakuriu

+1

@Bakuriu,很好。我不知道PEP可以这样改变。我会更新我的答案。然而,我仍然坚持我的观点,即拥有一个名称与顶级stdlib模块名称相同的打包模块不仅是允许的,而且是受到鼓励的。 – OozeMeister

相关问题