全局模块变量的多个实例?

时间:2013-07-30 20:09:42

标签: python

背景:我正在使用设备供应商提供的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

这似乎应该显而易见但有没有办法封装模块以​​便有多个实例可用?

5 个答案:

答案 0 :(得分:1)

我认为这是不可能的,因为Python模块的行为与Singletons非常相似(实际上这是在Python中创建Singleton的有效方法)。例如Refer to this SO threadthis 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