0

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

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

4

5 回答 5

2

以下似乎有效。它使用您的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]
于 2013-07-31T00:00:48.513 回答
1

我认为这是不可能的,因为 Python 模块的行为非常像单例(实际上这是在 Python 中创建单例的有效方法)。例如,请参阅此 SO 线程线程。这种设计旨在防止同一模块的多次导入,因为它可能有点昂贵。该logging模块就是一个很好的例子。您设置了一次记录器,所有由同一个解释器和导入运行的代码都logging将写入同一个日志文件。

于 2013-07-30T20:16:43.580 回答
1

在导入之间,您可以删除模块sys.modules以强制重新导入:

import sys
import module
del sys.modules['module']
import module as module2
print(module is module2) # prints False
于 2013-07-30T21:31:29.157 回答
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()
于 2013-07-30T20:46:57.573 回答
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()
于 2013-07-30T21:25:19.767 回答