简体   繁体   English

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

[英]Multiple instances of a global module variable?

Background: I'm working with a device vendor-supplied API module which stores device login data (device hostname, session ID, etc) as a global variable; 背景:我正在使用设备供应商提供的API模块,该模块将设备登录数据(设备主机名,会话ID等)存储为全局变量; I'm trying to figure out if it's possible to have multiple instances of the module to represent logins to multiple devices. 我试图弄清楚是否有可能有多个模块实例来表示登录到多个设备。

So far I've attempted a couple strategies with test code, none of which have worked: 到目前为止,我尝试了一些带有测试代码的策略,其中没有一个有效:

Test module code: statictest.py 测试模块代码:statictest.py

count = 0

class Test():
  @classmethod
  def testcount(cls):
    global count
    count += 1
    return count

First attempt: import module multiple times and instantiate: 首次尝试:多次导入模块并实例化:

>>> import statictest as s1
>>> import statictest as s2
>>> s1.Test.testcount()
1 
>>> s1.Test.testcount()
2
>>> s2.Test.testcount()
3

Second try: import module inside class, instantiate class: 第二次尝试:在类内部导入模块,实例化类:

#!/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()

That one didn't work either: 那个也不起作用:

[~/]$ ./moduletest.py 
1
2

This seems like it should be obvious but is there any way to encapsulate a module such that multiple instances are available? 这似乎应该是显而易见的,但有没有办法封装模块,以便多个实例可用?

I think it's not possible because Python modules pretty much behave like Singletons (in fact this is a valid method to create a Singleton in Python). 我认为这是不可能的,因为Python模块的行为非常像Singletons(实际上这是在Python中创建Singleton的有效方法)。 Refer to this SO thread or this one for example. 例如,请参考此SO线程 线程 This design is intended to prevent multiple imports of the same module because it can be somewhat expensive. 此设计旨在防止多次导入同一模块,因为它可能有些昂贵。 The logging module is an excellent example of this. logging模块就是一个很好的例子。 You set up your logger once and all your code which is being run by the same interpreter and imports logging will write to the same logfile. 您设置了一次记录器,并且由同一解释器和导入logging运行的所有代码将写入同一个日志文件。

The following seems to work. 以下似乎有效。 It uses your statictest.py module and a combination of a few of the ideas in other answers to create a context manager which will allow easy switching and use of any of the various instances of the module: 它使用您的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()

Sample output: 样本输出:

initial counts [2, 4, 4, 1]
calling instance[2].testcount()
counts after updating one of them [2, 4, 5, 1]

If you make copies of the file (statictest1.py, statictest2.py) that will work: 如果您制作可以使用的文件(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()

If the module's state is really well contained, you could write a context manager to swap the global state in and out of the module (ie monkey patch it) when you call it. 如果模块的状态确实很好,那么你可以编写一个上下文管理器来在调用它时将全局状态交换进模块(即猴子补丁)。

For instance: 例如:

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()

Between imports, you can delete the module from sys.modules to force it to be re-imported: 在导入之间,您可以从sys.modules删除该模块以强制重新导入该模块:

import sys
import module
del sys.modules['module']
import module as module2
print(module is module2) # prints False

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM