Следующий код работает правильно:

import pickle

class MyClass():   
    def __init__(self, arg):
        self.arg = arg

a = MyClass('my arg')
with open('/home/mahikeulbody/mypickle', 'wb') as file:
    pickle.dump(a, file)

Но добавив декоратор, чтобы получить мультитонный класс:

import pickle

def multiton(cls):
    instances = {}
    def getinstance(arg):
        if arg not in instances:
            instances[arg] = cls(arg)
        return instances[arg]
    return getinstance

@multiton
class MyClass():   
    def __init__(self, arg):
        self.arg = arg

a = MyClass('my arg')
with open('/home/michel/mypickle', 'wb') as file:
    pickle.dump(a, file)

Выдает следующую ошибку:

pickle.dump(a, file)
_pickle.PicklingError: Can't pickle <class '__main__.MyClass'>: it's not the same object as __main__.MyClass

Что случилось ?

1
mahikeulbody 24 Янв 2013 в 21:23

2 ответа

Лучший ответ

Пикл должен быть в состоянии загрузить класс напрямую. Ваш декоратор заменяет класс на фабричную функцию, что делает невозможным импортирование pickle самого класса.

Используйте отдельную фабричную функцию, а не декоратор, возвращая «закрытый» класс (но все же импортируемый напрямую):

class _MyClass():   
    def __init__(self, arg):
        self.arg = arg

def MyClass(arg, instances={}):
    if arg not in instances:
        instances[arg] = _MyClass(arg)
    return instances[arg]
2
Martijn Pieters 24 Янв 2013 в 17:26

Для этого я бы использовал укроп, который может сериализовать практически все в Python.

>>> def multiton(cls):
...     instances = {}
...     def getinstance(arg):
...         if arg not in instances:
...             instances[arg] = cls(arg)
...         return instances[arg]
...     return getinstance
... 
>>> @multiton
... class MyClass():   
...     def __init__(self, arg):
...         self.arg = arg
... 
>>> import dill
>>>                       
>>> a = MyClass('my arg')
>>> b = dill.loads(dill.dumps(a))
>>> a
<__main__.MyClass instance at 0x4d64558>
>>> b
<__main__.MyClass instance at 0x4d64800>

У Дилла также есть несколько хороших инструментов, которые помогут вам понять причину Ваше травление не удастся, когда ваш код потерпит неудачу.

0
Mike McKerns 17 Окт 2013 в 14:17