Ошибка Pickle при клонировании функции: не могу Pickle, это не тот же объект, что и - PullRequest
0 голосов
/ 21 июня 2019

Я сталкиваюсь с действительно странной проблемой при попытке клонировать функцию в Python, используя Как создать копию функции Python Техника

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

import dill
import pickle
import types

def foo():
    print ('a')

fooCopy=types.FunctionType(foo.__code__, foo.__globals__, 'IAmFooCopied',foo.__defaults__ , foo.__closure__)

print ( 'printing foo and the copy', fooCopy, foo )
print ( 'dill output: ', dill.dumps(fooCopy ))
print ( 'pickle Output: ', pickle.dumps (fooCopy) )

Выход:

printing foo and the copy <function foo at 0x7fb6ec6349d8> <function foo at 0x7fb6ed41a268>
dill output:  b'\x80\x03cdill._dill\n_create_function\nq\x00(cdill._dill\n_load_type\nq\x01X\x08\x00\x00\x00CodeTypeq\x02\x85q\x03Rq\x04(K\x00K\x00K\x00K\x02KCC\x0ct\x00d\x01\x83\x01\x01\x00d\x00S\x00q\x05NX\x01\x00\x00\x00aq\x06\x86q\x07X\x05\x00\x00\x00printq\x08\x85q\t)X\x10\x00\x00\x00testCloneFunc.pyq\nX\x03\x00\x00\x00fooq\x0bK\x05C\x02\x00\x01q\x0c))tq\rRq\x0ec__builtin__\n__main__\nX\x0c\x00\x00\x00IAmFooCopiedq\x0fNN}q\x10tq\x11Rq\x12.'
Traceback (most recent call last):
  File "testCloneFunc.py", line 12, in <module>
    print ( 'pickle Output: ', pickle.dumps (fooCopy) )
_pickle.PicklingError: Can't pickle <function foo at 0x7fb6ec6349d8>: it's not the same object as __main__.foo

Первое, что мне показалось странным, если что, если вы напечатаете копию, вы получите то же имя, что и оригинал, где я ожидал, что это будет «IAmFooCopied».

Тогда из-за ошибки, я полагаю, рассол также обманут, думая, что два объекта одинаковы.

Некоторые документы об этой ошибке рассола: https://code.google.com/archive/p/modwsgi/wikis/IssuesWithPickleModule.wiki

Но я действительно не понимаю, почему рассол не может видеть, что эти две функции не совпадают. Есть ли какое-нибудь быстрое решение, которое я могу использовать?

Редактировать: Кажется, что аргумент name типа FunctionType не устанавливает co_name функции, а устанавливает qualname . Поэтому, воссоздав кодовый объект, я исправил старую ошибку, чтобы встретиться с этой:

import dill
import pickle
import types

def foo():
    print ('a')


oldCode=foo.__code__

name='IAmFooCopied'

newCode= types.CodeType(
        oldCode.co_argcount,             #   integer
        oldCode.co_kwonlyargcount,       #   integer
        oldCode.co_nlocals,              #   integer
        oldCode.co_stacksize,            #   integer
        oldCode.co_flags,                #   integer
        oldCode.co_code,                 #   bytes
        oldCode.co_consts,               #   tuple
        oldCode.co_names,                #   tuple
        oldCode.co_varnames,             #   tuple
        oldCode.co_filename,             #   string
        name,                  #   string
        oldCode.co_firstlineno,          #   integer
        oldCode.co_lnotab,               #   bytes
        oldCode.co_freevars,             #   tuple
        oldCode.co_cellvars              #   tuple
        )


fooCopy=types.FunctionType(newCode, foo.__globals__, name,foo.__defaults__ , foo.__closure__)

fooCopy.__qualname__= name

print ( 'printing foo and the copy', fooCopy, foo )
print ( 'dill output: ', dill.dumps(fooCopy ))
print ( 'pickle Output: ', pickle.dumps (fooCopy) )

Новый вывод:

printing foo and the copy <function IAmFooCopied at 0x7fee8ebb19d8> <function foo at 0x7fee8f996268>
dill output:  b'\x80\x03cdill._dill\n_create_function\nq\x00(cdill._dill\n_load_type\nq\x01X\x08\x00\x00\x00CodeTypeq\x02\x85q\x03Rq\x04(K\x00K\x00K\x00K\x02KCC\x0ct\x00d\x01\x83\x01\x01\x00d\x00S\x00q\x05NX\x01\x00\x00\x00aq\x06\x86q\x07X\x05\x00\x00\x00printq\x08\x85q\t)X\x10\x00\x00\x00testCloneFunc.pyq\nX\x0c\x00\x00\x00IAmFooCopiedq\x0bK\x05C\x02\x00\x01q\x0c))tq\rRq\x0ec__builtin__\n__main__\nh\x0bNN}q\x0ftq\x10Rq\x11.'
Traceback (most recent call last):
  File "testCloneFunc.py", line 38, in <module>
    print ( 'pickle Output: ', pickle.dumps (fooCopy) )
_pickle.PicklingError: Can't pickle <function IAmFooCopied at 0x7fee8ebb19d8>: attribute lookup IAmFooCopied on __main__ failed

Кроме того, dill.detect не может обнаружить проблему.

Ответы [ 2 ]

0 голосов
/ 06 июля 2019

Я не уверен, что вы хотите сделать здесь ... но просто для ясности - dill работает как положено.

>>> import dill                                              
>>> import pickle
>>> import types
>>> 
>>> def foo():
...     print ('a')
... 
>>> fooCopy=types.FunctionType(foo.__code__, foo.__globals__, 'IAmFooCopied',foo.__defaults__ , foo.__closure__)
>>>
>>> dill.loads(dill.dumps(foo))
<function foo at 0x1058172a8>
>>> dill.loads(dill.dumps(fooCopy))
<function IAmFooCopied at 0x105817320>
>>> 

pickle не удается, потому что обычно не удается сериализоватьпользовательские функции во многих случаях, поскольку он сериализует функции по ссылке (т. е. по ссылке на модуль, в который он был встроен).Вы можете видеть в выгруженной строке, pickle в основном хранит строку, которая соответствует префиксу используемой версии сериализации, затем имени модуля (__main__), затем имени функции ('IAmFooCopied'),dill, с другой стороны, делает именно то, что вы делаете вручную.См. save_function и _create_function здесь: https://github.com/uqfoundation/dill/blob/master/dill/_dill.py.

0 голосов
/ 05 июля 2019

Вот код, который работает:

import pickle
import dill
import types

def foo():
    print ('a')


oldCode=foo.__code__

name='IAmFooCopied'

newCode= types.CodeType(
        oldCode.co_argcount,             #   integer
        oldCode.co_kwonlyargcount,       #   integer
        oldCode.co_nlocals,              #   integer
        oldCode.co_stacksize,            #   integer
        oldCode.co_flags,                #   integer
        oldCode.co_code,                 #   bytes
        oldCode.co_consts,               #   tuple
        oldCode.co_names,                #   tuple
        oldCode.co_varnames,             #   tuple
        oldCode.co_filename,             #   string
        name,                  #   string
        oldCode.co_firstlineno,          #   integer
        oldCode.co_lnotab,               #   bytes
        oldCode.co_freevars,             #   tuple
        oldCode.co_cellvars              #   tuple
        )

IAmFooCopied=types.FunctionType(newCode, foo.__globals__, name,foo.__defaults__ , foo.__closure__)
IAmFooCopied.__qualname__= name
print ( 'printing foo and the copy', IAmFooCopied, foo )
print ( 'dill output: ', dill.dumps(IAmFooCopied ))
print ( 'pickle Output: ', pickle.dumps (IAmFooCopied) )

Если определение функции (IAmFooCopied=types.FunctionType(newCode, foo.__globals__, name,foo.__defaults__ , foo.__closure__) и имя_меня = 'IAmFooCopied' enter code here не совпадают, pickle не может найти функцию длясериализация.

Вывод:

printing foo and the copy <function IAmFooCopied at 0x7f8a6a8159d8> <function foo at 0x7f8a6b5f5268>
dill output:  b'\x80\x03cdill._dill\n_create_function\nq\x00(cdill._dill\n_load_type\nq\x01X\x08\x00\x00\x00CodeTypeq\x02\x85q\x03Rq\x04(K\x00K\x00K\x00K\x02KCC\x0ct\x00d\x01\x83\x01\x01\x00d\x00S\x00q\x05NX\x01\x00\x00\x00aq\x06\x86q\x07X\x05\x00\x00\x00printq\x08\x85q\t)X\x10\x00\x00\x00testCloneFunc.pyq\nX\x0c\x00\x00\x00IAmFooCopiedq\x0bK\x05C\x02\x00\x01q\x0c))tq\rRq\x0ec__builtin__\n__main__\nh\x0bNN}q\x0ftq\x10Rq\x11.'
pickle Output:  b'\x80\x03c__main__\nIAmFooCopied\nq\x00.'
...