我正在使用Borg模式,相互包含模块。请参阅下面的示例代码(不是真实代码,但它显示了问题)。在这种情况下,我有两个不同的Borgs,因为类名(我猜这个类)被解释器视为不同。
在没有重新设计模块架构的情况下,有没有办法在这种情况下使用Borg?
模块borg.py
import borg2
class Borg:
_we_are_one = {}
def __init__(self):
self.__dict__ = Borg._we_are_one
try:
self.name
except AttributeError:
self.name = "?"
print self.__class__, id(self.__dict__)
def fct_ab():
a = Borg()
a.name = "Bjorn"
b = Borg()
print b.name
if __name__ == "__main__":
fct_ab()
borg2.fct_c()
模块borg2.py
import borg
def fct_c():
c = borg.Borg()
print c.name
结果是
__main__.Borg 40106720
__main__.Borg 40106720
Bjorn
borg.Borg 40106288
?
为了澄清我的问题:
为什么Python将__main__.Borg
和borg.Borg
视为两个不同的类?
答案 0 :(得分:4)
经过漫长的一天与Singletons和Borg的斗争后,我的结论如下:
似乎使用不同的“导入路径”多次导入的Python模块实际上是多次导入的。如果该模块包含单例,则会获得多个实例。
示例:
myproject/
module_A
some_folder/
module_B
module_C
如果module_A使用from myproject.some_folder import module_C
导入module_C并且module_B使用import module_C
导入相同的module_C,则模块实际导入两次(至少根据我的观察)。通常,这没关系,但对于单身人士或博格,你实际上得到了2个应该是唯一的实例。 (这是两组共享两个不同的内部状态)。
解决方案:给自己一个import语句约定并坚持下去:我从一个公共根文件夹开始导入所有模块,即使模块文件与我正在处理的模块文件平行,所以在上面的例子中,两者都是module_A和module_B使用from myproject.some_folder import module_C
导入module_C。
答案 1 :(得分:3)
问题只发生在你的主要功能中。移动该代码 到它自己的文件,一切都如你所料。这段代码
import borg
import borg2
if __name__ == "__main__":
borg.fct_ab()
borg2.fct_c()
提供此输出:
borg.Borg 10438672
borg.Borg 10438672
Bjorn
borg.Borg 10438672
Bjorn
答案 2 :(得分:1)
问题不在于班级名称。我不完全确定为什么Python看到Borg类和borg.Borg类不同,也许是因为你从__main__
运行它,我认为python没有意识到__main__
和borg是相同的模块。
解决方案很简单。将fct_ab更改为:
def fct_ab():
import borg
a = borg.Borg()
a.name = "Bjorn"
b = borg.Borg()
print b.name
这解决了这个问题。
答案 3 :(得分:0)
我通过修复导入中的错误修复了我的实际应用中的问题。
事实上,我有两个不同的模块使用相同的第三个模块。
第一个导入mypackage.mymodule而第二个导入mymodule。 mypackage作为python egg安装,我正在处理的代码在我的开发文件夹中。
所以这两个代码都导入了不同的模块,我想在这种情况下有两个不同的类是正常的。
关于我使用的示例代码,问题来自当前接收 main 作为名称的模块。我尝试通过__name__ = 'borg'
重命名。它有效,但它打破了if __name__ == "__main__"
的意见。作为结论,我想说必须避免相互包容,在大多数情况下是不必要的。
感谢大家的帮助。
答案 4 :(得分:0)
解决方案---正如已经提到的那样---是为了避免主模块的递归import
,但是borg.py
不是&#34 ;进口两次"。问题是在它已经执行时导入 at 导致你在两个不同的命名空间中定义Borg
类两次。
为了演示,我在borg.py
和borg2.py
的顶部添加了几行,并在大多数兴趣点之前和之后插入了我的print_module
函数:
#!/usr/bin/env python2
from __future__ import print_function
def print_module(*args, **kwargs):
print(__name__ + ': ', end='')
print(*args, **kwargs)
return
print_module('Importing module borg2...')
import borg2
print_module('Module borg2 imported.')
print_module('Defining class Borg...')
class Borg:
...
# etc.
输出结果为:
__main__: Importing module borg2...
borg2: Importing module borg...
borg: Importing module borg2...
borg: Module borg2 imported.
borg: Defining class Borg...
borg: id(_we_are_one) = 17350480
borg: Class Borg defined.
borg: id(Borg) = 139879572980464
borg: End of borg.py.
borg2: Module borg imported.
borg2: End of borg2.py.
__main__: Module borg2 imported.
__main__: Defining class Borg...
__main__: id(_we_are_one) = 17351632
__main__: Class Borg defined.
__main__: id(Borg) = 139879572981136
__main__: Borg 17351632
__main__: Borg 17351632
__main__: Bjorn
borg: Borg 17350480
borg2: ?
__main__: End of borg.py.
borg.py
做的第一件事(不计算我添加的位)是导入borg2
到__main__
命名空间。这发生在任何地方定义Borg
类之前。
borg2
做的第一件事就是导入borg
,它再次尝试导入borg2
......并且Python拒绝这样做。 (注意 nothing 在第3行和第4行之间发生。)borg
最终在Borg
命名空间中定义fct_ab
类和borg
函数,并退出。
borg2
定义fct_c
并退出(" borg2:borg2.py的结尾。")。所有import
语句都已完成。
现在,borg.py
终于执行" for real"。是的,它在导入时已经运行过一次,但这仍然是第一个"通过borg.py
文件的时间。 Borg
类再次定义,这次是在__main__
命名空间中,类及其字典都有新的ID。
borg.py
没有"两次输入"。它从命令行执行一次,并在导入时执行一次。由于这些发生在两个不同的命名空间中," second" Borg
的定义没有替换第一个,两个函数修改了两个不同的类,恰好是从同一个代码创建的。