我正在编写一个中等大小(一些KLOC)PyQt应用程序。我开始用漂亮的模块编写它以便于理解,但我正在研究Python命名空间的规则。在几个点上,重要的是仅将类的一个对象实例化为其他代码的资源。
例如:表示作为子进程附加的Aspell的对象,提供check(word)方法。另一个例子:该应用程序具有单个QTextEdit,而其他代码需要调用此单个对象的方法,例如“如果theEditWidget.document()。isEmpty()...”
无论我在哪里实例化这样的对象,它都只能从该模块中的代码引用,而不能引用其他代码。所以例如除非在同一模块中创建Aspell对象,否则编辑窗口小部件的代码无法调用Aspell网关对象。很好,除了其他模块也需要它。
在this question中提供了bunch类,但在我看来,一堆具有完全相同的问题:它是一个唯一的对象,只能在创建它的模块中使用。或者我在这里完全错过了船?
好的其他地方建议,这似乎是我的问题的简单答案。我刚刚测试了以下内容:
junk_main.py:
import junk_A
singularResource = junk_A.thing()
import junk_B
junk_B.handle = singularResource
print junk_B.look()
junk_A.py:
class thing():
def __init__(self):
self.member = 99
junk_B.py:
def look():
return handle.member
当我运行junk_main时,它打印99.所以主代码可以通过赋值将名称注入模块。我试图想出这是一个坏主意的原因。
答案 0 :(得分:2)
事实证明答案比我想象的要简单。正如我在问题中提到的,主模块可以为导入的模块添加名称。任何代码都可以将成员添加到对象中。因此,创建模块间通信区域的简单方法是在main中创建一个非常基本的对象,例如IMC(用于模块间通信器),并将其作为成员分配给其他模块应该可用的任何东西:
IMC.special = A.thingy()
IMC.important_global_constant = 0x0001
等。导入任何模块后,只需为其分配IMC:
import B
B.IMC = IMC
现在,从软件设计的角度来看,这可能不是最好的主意。如果你只是将IMC限制为保持命名常量,它就像一个C头文件。如果只是为了访问单一资源,它就像一个链接外部。但由于Python的自由规则,任何模块中的代码都可以修改或添加IMC成员。以无纪律的方式使用,“谁改变了”可能是一个调试问题。如果有多个过程,竞争条件就有危险。
答案 1 :(得分:1)
您可以使用.
运算符访问模块中的对象,就像使用函数一样。所以,例如:
# Module a.py
a = 3
>>> import a
>>> print a.a
3
这是一个简单的例子,但你可能想做类似的事情:
# Module EditWidget.py
theEditWidget = EditWidget()
...
# Another module
import EditWidget
if EditWidget.theEditWidget.document().isEmpty():
或者...
import * from EditWidget
if theEditWidget.document().isEmpty():
如果你选择import * from
路线,你甚至可以在你的模块中define a list named __all__,其中包含你希望模块输出到的所有对象的名称(作为字符串)列表*。因此,如果您只想导出编辑窗口小部件,则可以执行以下操作:
# Module EditWidget.py
__all__ = ["theEditWidget"]
theEditWidget = EditWidget()
...
答案 2 :(得分:1)
在几个方面,重要的是只将一个类的一个对象实例化为其他代码的资源。
您是否可以在程序的主要入口点和实例化需要它的对象之间的某处创建一次性对象,而不是尝试创建某种单件工厂?一次性对象可以作为参数传递给另一个对象。从逻辑上讲,您不会多次创建一次性对象。
例如:
def main(...):
aspell_instance = ...
myapp = MyAppClass(aspell_instance)
...或
class SomeWidget(...):
def __init__(self, edit_widget):
self.edit_widget = edit_widget
def onSomeEvent(self, ...):
if self.edit_widget.document().isEmpty():
....
我不知道这是否足够清楚,或者它是否适用于您的情况。但说实话,我发现自己无法做到这一点的唯一一次是基于CherryPy的网络服务器,其中的入口点几乎无处不在。