背景:我正在使用设备供应商提供的API模块,该模块将设备登录数据(设备主机名,会话ID等)存储为全局变量;我想弄清楚是否有可能有多个模块实例来表示登录到多个设备。
到目前为止,我尝试了一些带有测试代码的策略,其中没有一个有效:
测试模块代码:statictest.py
count = 0
class Test():
@classmethod
def testcount(cls):
global count
count += 1
return count
首次尝试:多次导入模块并实例化:
>>> import statictest as s1
>>> import statictest as s2
>>> s1.Test.testcount()
1
>>> s1.Test.testcount()
2
>>> s2.Test.testcount()
3
第二次尝试:在类中导入模块,实例化类:
#!/usr/bin/env python2.7
class TestMod():
s = __import__('statictest')
def test(self):
ts = self.s.Test()
return ts.testcount()
t = TestMod()
u = TestMod()
print t.test()
print u.test()
那个也不起作用:
[~/]$ ./moduletest.py
1
2
这似乎应该显而易见但有没有办法封装模块以便有多个实例可用?
答案 0 :(得分:1)
我认为这是不可能的,因为Python模块的行为与Singletons非常相似(实际上这是在Python中创建Singleton的有效方法)。例如Refer to this SO thread或this one。此设计旨在防止多次导入同一模块,因为它可能有些昂贵。 logging
模块就是一个很好的例子。您设置了一次记录器,并且由同一个解释器和导入logging
运行的所有代码将写入同一个日志文件。
答案 1 :(得分:1)
以下似乎有效。它使用您的statictest.py
模块以及其他答案中的一些想法的组合来创建上下文管理器,这将允许轻松切换和使用模块的任何各种实例:
from contextlib import contextmanager
import importlib
import random
import sys
MODULE_NAME = 'statictest'
NUM_INSTANCES = 4
instances = []
# initialize module instances
for _ in xrange(NUM_INSTANCES):
if MODULE_NAME in sys.modules:
del sys.modules[MODULE_NAME]
module = importlib.import_module(MODULE_NAME)
for _ in xrange(random.randrange(10)): # call testcount a random # of times
module.Test.testcount()
instances.append(sys.modules[MODULE_NAME])
@contextmanager
def statictest_inst(n):
save = sys.modules[MODULE_NAME]
sys.modules[MODULE_NAME] = instances[n]
yield instances[n]
sys.modules[MODULE_NAME] = save
def get_counts():
counts = []
for i in xrange(NUM_INSTANCES):
with statictest_inst(i) as inst:
counts.append(inst.count)
return counts
print 'initial counts', get_counts()
choice = random.randrange(NUM_INSTANCES)
print 'calling instance[{}].testcount()'.format(choice)
with statictest_inst(choice) as inst: # use context manager
inst.Test.testcount()
print 'counts after updating one of them', get_counts()
示例输出:
initial counts [2, 4, 4, 1]
calling instance[2].testcount()
counts after updating one of them [2, 4, 5, 1]
答案 2 :(得分:0)
如果你制作了可行的文件(statictest1.py,statictest2.py)的副本:
>>> import sttest1 as s1
>>> import sttest2 as s2
>>> s1.Test.testcount()
1
>>> s1.Test.testcount()
2
>>> s1.Test.testcount()
3
>>> s2.Test.testcount()
1
>>> s2.Test.testcount()
2
>>> s2.Test.testcount()
答案 3 :(得分:0)
如果模块的状态确实得到了很好的控制,你可以编写一个上下文管理器来调用模块中的全局状态(即猴子补丁)。
例如:
import mymodule
class ModuleState(object):
def __init__(self):
self.global_state = mymodule.global_state
def __enter__(self):
my_module.global_state = self.global_state
return self
def __exit__(self, type, value, traceback):
my_module.global_state = default_state
default_state = mymodule.global_state
# Init mymodule for state1
state1 = ModuleState()
# Init mymodule for state2
state2 = ModuleState()
# Init mymodule for state3
state3 = ModuleState()
# Do something in state2
with state2:
mymodule.something()
答案 4 :(得分:0)
在导入之间,您可以从sys.modules
删除该模块以强制重新导入该模块:
import sys
import module
del sys.modules['module']
import module as module2
print(module is module2) # prints False