我正试图“拦截”对特定模块的所有调用,并将它们重新路由到另一个对象。我想这样做,以便我可以拥有一个相当简单的插件架构。
例如,在main.py
中import renderer
renderer.draw('circle')
在renderer.py
中specificRenderer = OpenGLRenderer()
#Then, i'd like to route all calls from main.py so that
#specificRenderer.methodName(methodArgs) is called
# i.e. the above example would call specificRenderer.draw('circle')
这意味着任何函数都可以只导入渲染器并使用它,而不必担心细节。这也意味着我可以通过创建另一个对象并将其分配给renderer.py中的'specificRenderer'值来完全更改渲染器
有什么想法吗?
答案 0 :(得分:4)
在renderer.py
:
import sys
if __name__ != "__main__":
sys.modules[__name__] = OpenGLRenderer()
模块名称现在映射到OpenGLRenderer
实例,而其他模块中的import renderer
将获得相同的实例。
实际上,您甚至不需要单独的模块。你可以这样做:
import sys
sys.modules["renderer"] = OpenGLRenderer()
import renderer # gives current module access to the "module"
...主要模块中的第一件事。再次,在其他模块中导入renderer
将引用相同的实例。
你确定你真的想在第一时间这样做吗?人们对模块的行为并不是真的如此。
答案 1 :(得分:2)
最简单的方法是让main.py执行
from renderer import renderer
相反,只需命名为specificRenderer
renderer
。
答案 2 :(得分:2)
我的答案与@ kindall非常相似,尽管我在其他地方得到了这个想法。它更进一步,它将通常放在sys.modules
列表中的模块对象替换为您自己设计的类的实例。至少这样的课程需要看起来像这样:
档案renderer.py
:
class _renderer(object):
def __init__(self, specificRenderer):
self.specificRenderer = specificRenderer
def __getattr__(self, name):
return getattr(self.specificRenderer, name)
if __name__ != '__main__':
import sys
# from some_module import OpenGLRenderer
sys.modules[__name__] = _renderer(OpenGLRenderer())
__getattr__()
方法只是将大多数属性访问转发到真实的渲染器对象。这种间接级别的优势在于,您可以将自己的属性添加到私有_renderer
类,并通过导入的renderer
对象访问它们,就像它们是OpenGLRenderer
的一部分一样。对象。如果你给它们与OpenGLRenderer
对象中已经存在的名称相同,那么它们将被调用,可以在传递之前自由转发,记录,忽略和/或修改它 - 有时可能是非常方便。
放置在sys.modules
中的类实例实际上是单例,因此如果在应用程序的其他脚本中导入模块,它们将共享由第一个创建的单个实例。
答案 3 :(得分:0)
编辑:这个答案不符合OP的要求;它不实例化一个对象,然后让对模块的调用重定向到同一个对象。这个答案是关于改变使用哪个渲染模块。
最简单的可能是在main.py程序中导入OpenGLRenderer,如下所示:
import OpenGLRenderer as renderer
这个代码只在一个地方,在你的模块的其余部分中,OpenGLRenderer可以称为renderer
。
如果您有几个模块,例如main.py,您可以将renderer.py文件放在同一行:
import OpenGLRenderer as renderer
然后其他模块可以使用
from renderer import renderer
如果OpenGLRenderer还没有完全嘎嘎叫,你可以在renderer.py模块中根据需要对它进行monkeypatch工作。
答案 4 :(得分:0)
如果您不介意import renderer
导致对象而不是模块,那么请参阅kindall的精彩解决方案。
如果您希望@property
正常工作(即每次提取renderer.mytime
,您希望调用与OpenGLRenderer.mytime
对应的功能),并且您希望保留renderer
作为一个模块,那是不可能的。例如:
import time
class OpenGLRenderer(object):
@property
def mytime(self):
return time.time()
如果您不关心属性,即mytime
仅被调用一次(在模块加载时),并且它将继续返回相同的时间戳,那么可以通过将所有符号从对象复制到模块:
# renderer.py
specificRenderer = OpenGLRenderer()
for name in dir(specificRenderer):
globals()[name] = getattr(specificRenderer, name)
然而,这是一次性复制。如果稍后动态地向specificRenderer
添加方法或其他属性,或稍后更改某些属性,则它们不会自动复制到renderer
模块。但是,这可以通过一些丑陋的__setattr__
黑客来解决。