Подтвердить что ты не робот

Травление динамически генерируемых классов?

Я использую 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)
4b9b3361

Ответ 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)

Конечно, вам нужно убедиться, что имена ваших классов уникальны.