【问题标题】:Pickle error while cloning a function : Can't pickle it's not the same object as克隆函数时出现泡菜错误:不能泡菜它不是同一个对象
【发布时间】:2019-06-21 12:44:26
【问题描述】:

我在尝试使用How to create a copy of a python function技术在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”。

那么对于这个错误,我猜 pickle 也被欺骗认为这两个对象是相同的。

关于这个泡菜错误的一些文档:https://code.google.com/archive/p/modwsgi/wikis/IssuesWithPickleModule.wiki

但是我真的不明白为什么pickle看不到这两个功能不一样。有什么我可以使用的快速修复方法吗?

编辑:似乎FunctionType的name参数没有设置函数的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 无法检测到任何问题。

【问题讨论】:

  • 另外,如果你写了-1,请解释原因

标签: python-3.x pickle python-internals dill


【解决方案1】:

我不确定你想在这里做什么...但要明确一点——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_functionhttps://github.com/uqfoundation/dill/blob/master/dill/_dill.py

【讨论】:

    【解决方案2】:

    这是有效的代码:

    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__)和name='IAmFooCopied'不匹配,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.'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多