【问题标题】:importing a module and altering the module behavior at import导入模块并在导入时更改模块行为
【发布时间】:2011-08-14 00:07:04
【问题描述】:

我想导入一个模块,但是根据我想要施加的一些外部条件,导入的行为可能会有所不同。有哪些策略可以实现这一结果?

例子。我想要一个模块 foo.py。如果我import foo 我会打印“你好”或“再见”,这取决于一些独立于模块的外部条件,而是依赖于外部因素。一个微不足道的可能是一个全局变量,但我不认为 python 范围规则允许我从模块 foo 之外获取全局变量。

例子:

fop.py

import __main__
try:
    __main__.bar
    present = True
except:
    present = False

if present:
    print "present"
else:
    print "not present"

现在,当我导入模块时,我可以获得不同的结果

Python 2.7.1 (r271:86832, Feb 27 2011, 20:04:04) 
[GCC 4.2.1 (Apple Inc. build 5664)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import foo
not present
>>> 

Python 2.7.1 (r271:86832, Feb 27 2011, 20:04:04) 
[GCC 4.2.1 (Apple Inc. build 5664)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> bar = 5
>>> import foo
present

我知道这很奇怪,但我有一个非常、非常、非常好的理由这样做。

【问题讨论】:

  • 听起来像没有人能理解的代码......
  • 塞巴斯蒂安:这正是我想要实现的目标
  • 你能举一个用例的例子吗?比如外部条件的例子,什么是“行为不同”?
  • 啊,好吧,在这种情况下,您应该检查一下 twisted.internet.reactor,这对我来说似乎是个好方法。
  • 你可以通过 import hooks 调用各种东西:python.org/dev/peps/pep-0302

标签: python


【解决方案1】:

传递有关环境的数据的标准方法是(自然地)使用环境变量:

>>> import os
>>> os.environ['PY_BAR'] = '1'
>>> import foo
"present"

另一种可能的模式是实现一个自定义的import例程/钩子,这样当foo被导入时,下面提到的初始化例程可以在模块加载之后但控制之前静默执行返回。


扩展 Sven 的模式,你可以明确地初始化 foo 模块,以便外部环境可以影响它。这会创建一个定义明确、记录在案的接口,用于在使用 foo 模块之前将其注入:

定义 foo.py 模块:

# define all your classes and functions, then leave global stubs which will 
# be filled in by the module initialization function init(), which _must_ be
# called before the module is used.

_DATA = {}

def use_data():
    # use '_DATA' to do something useful
    ...

def init(state):
    # use 'state' to populate '_DATA'
    ...

定义脚本:

# main configures the state, passing it explicitly to foo
state = {'variable': 42}
import foo
foo.init(state)
foo.use_data()

【讨论】:

  • 不,这不起作用。我想控制模块导入,而不是在它之后。
【解决方案2】:

您可以使用virtual module 像这样您可以在某个地方定义您的模块,将您想要的所有内容放入其中,并且每次导入它时,您都会得到这个虚拟模块,而不是原始模块。当外部条件发生变化时,您只需重做整个事情并将其他内容放入模块中。

如果您有不同的文件用于不同的行为,您还可以在其__init__.py 中更改包的搜索路径,如果您的条件发生变化,您只需将其从 sys.modules 中删除,以便它实际上重新加载到下次导入。

【讨论】:

    【解决方案3】:

    您实际上可以从模块内部访问主脚本的全局变量。

    在主脚本中:

    a = 42
    import foo
    

    foo.py:

    import __main__
    print __main__.a
    

    请注意,我只是说这是可能的:)

    【讨论】:

    • 这很好。其他实现相同的方法?
    猜你喜欢
    • 1970-01-01
    • 2015-10-06
    • 1970-01-01
    • 2021-12-08
    • 1970-01-01
    • 2016-11-07
    • 2018-10-28
    • 1970-01-01
    • 2012-08-27
    相关资源
    最近更新 更多