Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 通过多重处理传递类似dict的对象。队列使其无法通过属性进行修改_Python_Multiprocessing - Fatal编程技术网

Python 通过多重处理传递类似dict的对象。队列使其无法通过属性进行修改

Python 通过多重处理传递类似dict的对象。队列使其无法通过属性进行修改,python,multiprocessing,Python,Multiprocessing,实际上,我不确定标题是否恰当地描述了这个问题。让我看看代码 import os from multiprocessing import JoinableQueue # A dict-like class, but is able to be accessed by attributes. # example: d = AttrDict({'a': 1, 'b': 2}) # d.a is equivalent to d['a'] class AttrDict(dict): def __

实际上,我不确定标题是否恰当地描述了这个问题。让我看看代码

import os
from multiprocessing import JoinableQueue

# A dict-like class, but is able to be accessed by attributes.
# example: d = AttrDict({'a': 1, 'b': 2})
# d.a is equivalent to d['a']
class AttrDict(dict):
    def __init__(self, *args, **kwargs):
        super(AttrDict, self).__init__(*args, **kwargs)
        self.__dict__ = self


queue = JoinableQueue()
pid = os.fork()

if pid == 0:
    d = AttrDict({'a': 1, 'b': 2})
    queue.put(d)
    queue.join()
    os._exit(0)
else:
    d = queue.get()
    queue.task_done()
    #d = AttrDict(d.items())  #(1)
    d.a = 3                   #(2)
    #d['a'] = 3               #(3)
    print d
上面的代码打印出
{'a':1,'b':2}
,这意味着(2)不起任何作用

如果将(2)更改为(3)或启用(1),则输出为
{'a':3,'b':2}
,这是预期的

当它通过队列时,
d
似乎发生了什么事情

使用Python2.7进行测试


解决方案:

正如@kindall和@Blckknght所指出的,原因是
d
被选为一个dict,当它被
queue.get()
取消勾选时,
self.\uu dict\uuuu=self
魔术没有设置。差异可以通过
print d.\uu dict\uu
print d
来体现

为了恢复魔术,我将方法
\uuu setstate\uuu
添加到
AttrDict

class AttrDict(dict):
    def __init__(self, *args, **kwargs):
        super(AttrDict, self).__init__(*args, **kwargs)
        self.__dict__ = self

    def __setstate__(self, state):
        self.__dict__ = state

代码现在按预期工作。

我的猜测是,由于它是
dict
的子类,因此您的
AttrDict
被序列化为
dict
。特别是指向
自身的
\uuuu dict\uuu
可能不会被保留。您可以使用某些神奇的方法自定义序列化;请参阅。

这实际上不是一个多处理问题,因为
多处理。Queue
使用
pickle
对通过它发送的对象进行序列化和取消序列化。问题在于
pickle
没有正确保存设置
self时获得的“神奇”行为

如果您检查在子进程中得到的对象,您会发现它的
\uuu dict\uuu
只是一个普通的字典,其内容与对象本身相同。在对象上设置新属性时,其
\uuuu dict\uuu
会更新,但继承的字典
self
不会更新。我的意思是:

>>> d = AttrDict({"a":1, "b":2})
>>> d2 = pickle.loads(pickle.dumps(d, -1))
>>> d2
{'a': 1, 'b': 2}
>>> d2.b = 3
>>> d2
{'a': 1, 'b': 2}
>>> d2.__dict__
{'a': 1, 'b': 3}
虽然您可以深入了解
pickle
如何工作的细节,并让序列化再次工作,但我认为一种更简单的方法是通过让类重写
\uuu getattr\uuuu
\uu setattr\uuuuuu
\uuu delattr\uuuuuu>方法来依赖不那么神奇的行为:

class AttrDict(dict):
    __slots__ = () # we don't need a __dict__

    def __getattr__(self, name): # wrapper around dict.__setitem__, with an exception fix
        try:
            return self[name]
        except KeyError:
            raise AttributeError(name) from None # raise the right type of exception

    def __delattr__(self, name): # wrapper around dict.__delitem__
        try:
            del self[name]
        except KeyError:
            raise AttributeError(name) from None # change exception type here too

    __setattr__ = dict.__setitem__ # no special exception rewriting needed here
该类的实例将与您自己的实例一样工作,但可以成功地对其进行pickle和unpickle:

>>> d = AttrDict({"a":1, "b":2})
>>> d2 = pickle.loads(pickle.dumps(d, -1)) # serialize and unserialize
>>> d2
{'a': 1, 'b': 2}
>>> d2.b=3
>>> d2
{'a': 1, 'b': 3}

您的实现更加明确。我会考虑的。非常感谢。