【问题标题】:Python - dill: Can't pickle decorated classPython - 莳萝:不能腌制装饰类
【发布时间】:2026-01-10 07:50:01
【问题描述】:

我有以下代码,用于装饰类:

import dill
from collections import namedtuple
from multiprocessing import Process

def proxified(to_be_proxied):
    b = namedtuple('d', [])

    class Proxy(to_be_proxied, b):
        pass

    Proxy.__name__ = to_be_proxied.__name__
    return Proxy


@proxified
class MyClass:
    def f(self):
        print('hello!')


pickled_cls = dill.dumps(MyClass)


def new_process(clazz):
    dill.loads(clazz)().f()


p = Process(target=new_process, args=(pickled_cls,))
p.start()
p.join()

当我尝试腌制装饰类时,出现以下错误:

Traceback (most recent call last):
  File "/usr/lib/python3.5/pickle.py", line 907, in save_global
    obj2, parent = _getattribute(module, name)
  File "/usr/lib/python3.5/pickle.py", line 265, in _getattribute
    .format(name, obj))
AttributeError: Can't get local attribute 'proxified.<locals>.Proxy' on <function proxified at 0x7fbf7de4b8c8>

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/carbolymer/example.py", line 108, in <module>
    pickled_cls = dill.dumps(MyClass)
  File "/usr/lib/python3.5/site-packages/dill/dill.py", line 243, in dumps
    dump(obj, file, protocol, byref, fmode, recurse)#, strictio)
  File "/usr/lib/python3.5/site-packages/dill/dill.py", line 236, in dump
    pik.dump(obj)
  File "/usr/lib/python3.5/pickle.py", line 408, in dump
    self.save(obj)
  File "/usr/lib/python3.5/pickle.py", line 475, in save
    f(self, obj) # Call unbound method with explicit self
  File "/usr/lib/python3.5/site-packages/dill/dill.py", line 1189, in save_type
    StockPickler.save_global(pickler, obj)
  File "/usr/lib/python3.5/pickle.py", line 911, in save_global
    (obj, module_name, name))
_pickle.PicklingError: Can't pickle <class '__main__.proxified.<locals>.Proxy'>: it's not found as __main__.proxified.<locals>.Proxy

如何使用 dill 腌制装饰类?我想将此类作为参数传递给单独的进程 - 也许有更简单的方法吗?

【问题讨论】:

  • 你在这个例子中发生了很多事情,其中​​很多事情很难序列化。首先,我建议使用multiprocess 而不是multiprocessing,所以你使用dill 而不是pickle。其次,尽可能避免使用namedtuple。它们将序列化,但仅在某些情况下有效。第三,尽可能避免使用类装饰器。我不记得dill 和他们相处得有多好,我觉得很糟糕。最后,您可以尝试不同的dill.settings,以了解dill 处理全局变量的方式。首先,使用multiprocess,不要使用namedtuple

标签: python class decorator pickle dill


【解决方案1】:

Gaël Varoquaux can be found here 提供了“为什么酸洗装饰函数很痛苦”的一个很好的解释。

基本上使用functools.wraps重写类可以避免这些问题:)

【讨论】: