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.

4

3 回答 3

4

可能会导入各种包含“req”的模块,而您不知道它是否是您真正要查找的模块:

>>> 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'

包的全部意义在于模块层次结构有命名空间。如果用户碰巧导入了一些恰好包含名称冲突的模块的库,则“从任何包”查找模块名称只会导致您的代码随机中断。

于 2010-02-23T22:18:01.353 回答
1

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

于 2010-02-23T22:28:17.200 回答
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")
于 2010-02-24T01:09:28.110 回答