2010-02-23 35 views
2

我刚开始尝试使用一种我称之为“模块鸭子打字”的新技术(至少现在是这样)。模块“鸭子打字”陷阱?

例子:

主模块

import somepackage.req ## module required by all others 
import abc 
import Xyz 

模块abc

__all__=[] 

def getBus(): 
    """ Locates the `req` for this application """ 
    for mod_name in sys.modules: 
     if mod_name.find("req") > 0: 
      return sys.modules[mod_name].__dict__["Bus"] 
    raise RuntimeError("cannot find `req` module") 

Bus=getBus() 

在模块abc我并不需要明确import req:它可以在包在任何地方层次结构。当然这需要一些训练...

使用这种技术,可以很容易地重新定位层次结构中的软件包。

有没有陷阱等着我?例如移动到Python 3K

更新:经过一些更多的测试后,我决定直接返回到sys.path插入包的依赖关系。

+1

'mod_name.find(“req”)> 0'并不真正代表您的意思。如果我有一个名为'frequency'的模块怎么办? – 2010-02-23 22:20:06

+1

'sys.modules [mod_name] .__ dict __ [“Bus”]'拼写为'sys.modules [mod_name] .Bus'。 – 2010-02-23 22:20:45

+0

@Mike Graham:是的......正在进行中,因为我已经评论过了。谢谢。 – jldupont 2010-02-23 22:25:15

回答

4

可能有各种含有“请求”导入模块的,你不知道这是否是你实际上是在寻找该模块:

>>> import urllib.request 
>>> import tst 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "tst.py", line 12, in <module> 
    Bus=getBus() 
    File "tst.py", line 9, in getBus 
    return sys.modules[mod_name].__dict__["Bus"] 
KeyError: 'Bus' 

包的整点是有命名空间为模块层次结构。如果用户碰巧导入一些碰巧包含名称冲突的模块的库,那么查找“来自任何包”的模块名称只会导致您的代码随机中断。

+0

+1:好点:我需要更精确地使用我的“模式匹配”。考虑这个“正在进行中的工作”;-) – jldupont 2010-02-23 22:18:52

1

这种技术很危险且容易出错。它可以与您的测试一起工作,直到有人导入新的something.req,并得到一个令人困惑的,遥远的错误。 (这是最好的情况,当前的实现会跳转到其他许多模块上。)如果重新构建包,那么很容易在那个时候以自动的方式修改你的代码而不用任何魔法。 Python可以做各种神奇的,动态的事情,但这并不意味着我们应该做。

0

我觉得这更像鸭子打字。我还建议使用比“总线”更独特的标识符

def getBus(): 
    """ Locates the Bus for this application """ 
    for mod in sys.modules.values(): 
     if hasattr(mod, 'Bus') and type(mod.Bus) is...: # check other stuff about mod.Bus 
      return mod.Bus 
    raise RuntimeError("cannot find Bus")