Травление динамически генерируемых классов?
Я использую type()
для динамического создания классов, которые в конечном итоге будут мариноваться. Проблема состоит в том, что для процесса без травления требуется определение класса, чтобы перестроить объект, который был маринован.
Вот где я застрял. Я не знаю, как каким-то образом предоставить unpickler способ генерации экземпляра из класса, который был динамически сгенерирован.
Любые подсказки оценены.
Спасибо!
Вот пример проблемы:
>>> class Foo(object):
... pass
>>> g=type('Goo',(Foo,),{'run':lambda self,x: 2*x } )()
>>> cPickle.dumps(g)
PicklingError: Can't pickle <class '__main__.Goo'>: attribute lookup __main__.Goo failed
Это, очевидно, работает, но только из динамических классов, созданных из базового класса, способного размножаться (с определением наход щегося в модуле):
import cPickle
class Foo(object): pass
def dynamic(): return type('Goo',(Foo,),{'run':lambda self,x: 2*x } )()
g=type('Goo',(Foo,),{'run':lambda self,x: 2*x , '__reduce__': lambda self: (dynamic,tuple()) } )()
gg=cPickle.loads ( cPickle.dumps(g) )
print gg.run(10)
Ответы
Ответ 1
Когда Pickler встречает объект типа, о котором он ничего не знает, он ищет метод . Определение этого метода при создании пользовательского класса с использованием типа должно решить проблему травления.
Если вы предоставляете начальные аргументы, то вам, возможно, потребуется определить метод getnewargs
Ответ 2
Одна идея заключалась бы в том, чтобы рассортировать кортеж с помощью:
- Имя динамического класса
- Кортеж подкласса (возможно, в строковой форме от repr())
- Словарь классов
- Фактический экземпляр
Это позволит вам рассортировать класс, а затем восстановить его позже, используя type() и подклассификацию Unpickler.
Ответ 3
Для нединамических классов механизм трассировки питона записывает имя модуля и класса в виде строк. В разное время он автоматически загружает объект класса из этого модуля.
Как уже упоминалось в исходном сообщении, проблема здесь в том, что для динамических классов само определение класса не маринованными сортировщиком по умолчанию. Поскольку динамические классы не существуют в исходном файле модуля, рассыпание динамического класса обычно не будет работать.
Самая сложная часть травления самого класса - это хранение байт-кода методов. Похороненный в PiCloud, там есть улучшенный pickler под капотом, который может раскрыть динамические функции, которые вы, вероятно, могли бы использовать или расширять для обработки ваших объектов.
Ответ 4
Вы можете назначить глобальное имя вашему динамически сгенерированному классу, чтобы сделать его picklable.
>>> class Foo(object):
... pass
>>> class_name = 'Goo'
>>> my_class = type(class_name, (Foo, ), {'run': lambda self, x: 2*x })
>>> globals()[class_name] = my_class
>>> g = my_class()
>>> pickle.dumps(g)
Конечно, вам нужно убедиться, что имена ваших классов уникальны.
Ответ 5
Я никогда не делал этого сам, но http://docs.python.org/library/pickle.html#subclassing-unpicklers, кажется, указывает, что вы можете переопределить поведение путем подкласса Unpickler