能否向导入的模块全局变量注入一个模块?

5

我有一个文件hello.py,其中包含一个名为hello()的函数。

hello.py

def hello():
    print "hello world"

我有另一个文件test.py,它导入了hello并调用了函数。

test.py:

from hello import *

def run():
    hello()

if __name__ == '__main__':
    run()

如果我通过Python运行test.py,它会按预期工作:
$ python test.py
hello world

现在,我要编辑test.py,并且删除导入语句

test.py:

def run():
    hello()    # hello is obviously not in scope here

if __name__ == '__main__':
    run()

我介绍一个第三个文件,run.py,它同时导入了hello.pytest.py

run.py:

from hello import *
from test import *

if __name__ == '__main__':
    run()

自然地,这是无法工作的,因为hello()不在test.py的范围内。
$ python run.py 
Traceback (most recent call last):
  File "run.py", line 5, in <module>
    run()
  File "test.py", line 4, in run
    hello()
NameError: global name 'hello' is not defined

问题:

  • 是否可以在不让run.py导入hello.py的情况下,从run.pyhello()注入到test.py的作用域中?

如果需要,我可以使用较低级别的功能,例如imp模块。


3
可以实现,但隐藏依赖关系从来都不是一个好主意。 - wim
@wim,暂时不讨论是否是一个好主意,如果可能的话,请您分享如何做到的? - Steve Lorimer
记录一下,from hello import *确实在导入hello.py。只是它没有在run.py的全局命名空间中绑定一个模块名称而已。接着使用import hello将不涉及第二次导入,它只会从缓存中提取已经导入的模块。 - ShadowRanger
@SteveLorimer:你搞反了。不应该让你的 C++ 代码将一个模块注入到 Python 脚本的全局变量中,而是应该让 Python 导入由 C++ 代码暴露的模块。 - user2357112
“该模块仅存在于我的C++应用程序中。” - 不,模块的存在并不是这样工作的。在您的嵌入式解释器中运行的Python代码应该可以很好地导入它。 - user2357112
显示剩余3条评论
3个回答

6
是的。模块的属性就是它的全局变量,所以你只需将其插入其中即可。
import test
import hello
test.hello = hello.hello

我要重申wim的评论,这通常不是一个好主意。

简单明了!谢谢!我完全理解这不是一个好主意,所以也许你可以看一下这个问题,并提供一个更好的解决方案,我会非常感激。 - Steve Lorimer

2

模块是可变的:

import hello
import test

test.hello = hello.hello

if __name__ == '__main__':
    test.run()

0
你所描述的听起来很像一个类。如果它看起来像一个类,说起话来也像一个类,那么它就是一个类。
在 hello.py 文件中:
class Hello(object):
    @classmethod
    def hello(class_):
        print("Hello, world!")

test.py 文件中:
class Test(object):
    @classmethod
    def run(class_):
        class_.hello()

run.py 文件中:
import hello
import test

class Run(hello.Hello, test.Test):
    pass

if __name__ == '__main__':
    # Note: we don't instantiate the class.
    Run.run()

这并不会给你完全相同的语法,因此它并不能直接回答你的问题,但是它可以提供你所寻找的相同功能,而不需要采用意外的黑客手段,比如修改其他模块。

我所描述的并不是解决这个问题的唯一方法,但是让一个模块修改另一个模块可能是你的代码工作的相当令人惊讶的方式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接