python 经理注册问题或我的错误代码

python manager register issue or just my faulty code

我使用 python 管理器在进程之间共享数据。我想将我的代码分解成更小的部分,并创建了一个函数 'soFactory',它将采用 name/object 对的字典,并以给定的名称向管理器注册对象。 在下面的简单示例中,我创建了两个列表并将它们注册到管理器。如果我使用 soFactory 经理 returns 只有列表之一(最后一个注册),无论我引用哪个名称。 如果我解开 soFactory 的逻辑,我可以通过引用它们的注册名称来访问正确的对象。 我一定是遗漏了一些明显但没有看到的东西。

# ------------ prototype for SO question -------
from sys import stderr

def soFactory(dictofSo, manager):
    """shared object factory"""
    for n,t in dictofSo.items():
        print >>stderr, 'created item',n,t
        manager.register(n, callable=lambda: t)

def soRoutine(n, t, manager):
    manager.register(n, callable=lambda: t)

def test_soFactory(useFactory=True):
    """tests the soFactory function"""
    from multiprocessing import managers
    m = managers.BaseManager(address='/var/tmp/tqps-test', authkey='abc123')
    mySOlist = {'L1': [1],'L2':[2]}

    if useFactory:
        soFactory(mySOlist, m)
    else:
        for n, t in mySOlist.items():
            soRoutine(n, t, m)

    m.start()

    m.L1().append('only in L1!')
    print >>stderr, m.L1(), m.L2()

>>> test_soFactory()
created item L2 [2]
created item L1 [1]
[1, 'only in L1!'] [1, 'only in L1!']

>>> test_soFactory(useFactory=False)
[1, 'only in L1!'] [2]
>>> 

这是一个常见的 python 变量范围陷阱,这是由于 lambda 创建的闭包记住了变量的名称,而不是对象(或 "pointer") .当调用 lambda 时, t的值是在周围作用域中查找的,此时循环已经结束,所以t赋值其最终值L1,当然这个要看顺序return 的 dictofSo.items() 值。

您可以通过打开 multiprocessing:

的调试日志来确认这一点
import logging
import multiprocessing
multiprocessing.util.log_to_stderr(logging.DEBUG)

L1L2 具有相同的 ID:

[DEBUG/MainProcess] requesting creation of a shared 'L1' object
[DEBUG/BaseManager-1] 'L1' callable returned object with id '104aef878'
[DEBUG/MainProcess] INCREF '104aef878'
...
[DEBUG/MainProcess] requesting creation of a shared 'L2' object
[DEBUG/BaseManager-1] 'L2' callable returned object with id '104aef878'

当你在函数soRoutine()中创建lambda时,因为函数会创建一个新的局部作用域,所以这一次t可以指向你期望的值。另见 this post.