有没有简单的方法来 pickle 一个 python 函数(或者以其他方式序列化它的代码)?

2025-02-27 09:07:00
admin
原创
62
摘要:问题描述:我正在尝试通过网络连接传输一个函数(使用 asyncore)。有没有一种简单的方法来序列化一个 Python 函数(至少在这种情况下,不会产生副作用)以便进行这样的传输?我理想情况下希望有一对类似于以下的功能:def transmit(func): obj = pickle.dumps(fu...

问题描述:

我正在尝试通过网络连接传输一个函数(使用 asyncore)。有没有一种简单的方法来序列化一个 Python 函数(至少在这种情况下,不会产生副作用)以便进行这样的传输?

我理想情况下希望有一对类似于以下的功能:

def transmit(func):
    obj = pickle.dumps(func)
    [send obj across the network]

def receive():
    [receive obj from the network]
    func = pickle.loads(s)
    func()

解决方案 1:

您可以序列化函数字节码,然后在调用者上重建它。marshal模块可用于序列化代码对象,然后可以将其重新组装成函数。即:

import marshal
def foo(x): return x*x
code_string = marshal.dumps(foo.__code__)

然后在远程进程中(传输code_string之后):

import marshal, types

code = marshal.loads(code_string)
func = types.FunctionType(code, globals(), "some_func_name")

func(10)  # gives 100

一些注意事项:

  • marshal 的格式(就此而言任何 python 字节码)可能与主要的 python 版本不兼容。

  • 仅适用于 cpython 实现。

  • 如果函数引用了您需要获取的全局变量(包括导入的模块、其他函数等),您也需要序列化它们,或者在远程端重新创建它们。我的示例只是为其提供了远程进程的全局命名空间。

  • 您可能需要做更多的事情来支持更复杂的情况,例如闭包或生成器函数。

解决方案 2:

查看Dill,它扩展了 Python 的 pickle 库以支持更多类型,包括函数:

>>> import dill as pickle
>>> def f(x): return x + 1
...
>>> g = pickle.dumps(f)
>>> f(1)
2
>>> pickle.loads(g)(1)
2

它还支持对函数闭包中的对象的引用:

>>> def plusTwo(x): return f(f(x))
...
>>> pickle.loads(pickle.dumps(plusTwo))(1)
3

解决方案 3:

最简单的方法可能是inspect.getsource(object)(参见检查模块)它返回一个包含函数或方法源代码的字符串。

解决方案 4:

Pyro能够为您做到这一点。

解决方案 5:

这完全取决于您是否在运行时生成该函数:

如果这样做 -inspect.getsource(object)将不适用于动态生成的函数,因为它从.py文件中获取对象的源,因此只有在执行之前定义的函数才能作为源被检索。

如果您的函数无论如何都放在文件中,为什么不让接收者访问它们并只传递模块和函数名称。

我能想到的动态创建函数的唯一解决方案是在传输之前将函数构造为字符串,传输源,然后eval()在接收端传输它。

编辑:这个marshal解决方案看起来也很聪明,不知道你还能序列化其他内置的东西

解决方案 6:

在现代 Python 中,你可以 pickle 函数和许多变体。考虑一下

import pickle, time
def foobar(a,b):
    print("%r %r"%(a,b))

你可以腌制它

p = pickle.dumps(foobar)
q = pickle.loads(p)
q(2,3)

你可以腌制封口

import functools
foobar_closed = functools.partial(foobar,'locked')
p = pickle.dumps(foobar_closed)
q = pickle.loads(p)
q(2)

即使闭包使用局部变量

def closer():
    z = time.time()
    return functools.partial(foobar,z)
p = pickle.dumps(closer())
q = pickle.loads(p)
q(2)

但如果你使用内部函数关闭它,它就会失败

def builder():
    z = 'internal'
    def mypartial(b):
        return foobar(z,b)
    return mypartial
p = pickle.dumps(builder())
q = pickle.loads(p)
q(2)

有错误

pickle.PicklingError: 无法 pickle <function mypartial at 0x7f3b6c885a50>: 未找到 __ main __.mypartial

已使用 Python 2.7 和 3.6 进行测试

解决方案 7:

cloud包 (pip install cloud) 可以 pickle 任意代码,包括依赖项。请参阅https://stackoverflow.com/a/16891169/1264797

解决方案 8:

代码字符串 = '''
定义 foo(x):
    返回 x * 2
定义条形图(x):
    返回 x ** 2
'''

obj = pickle.dumps(代码字符串)

现在

执行(pickle.loads(obj))

foo(1)
> 2
酒吧(3)
> 9

解决方案 9:

Cloudpickle可能就是您正在寻找的。Cloudpickle 的描述如下:

cloudpickle 对于集群计算尤其有用,其中 Python 代码通过网络传输到远程主机上执行,可能靠近数据。

使用示例:

def add_one(n):
  return n + 1

pickled_function = cloudpickle.dumps(add_one)
pickle.loads(pickled_function)(42)

解决方案 10:

您可以这样做:

def fn_generator():
    def fn(x, y):
        return x + y
    return fn

现在,transmit(fn_generator())将发送模块名称的实际定义fn(x,y)而不是引用。

您可以使用相同的技巧通过网络发送课程。

解决方案 11:

该模块使用的基本功能涵盖了您的查询,此外您还可以通过网络获得最佳压缩;请参阅指导性源代码:

y_serial.py 模块:: 使用 SQLite 仓库 Python 对象

“序列化 + 持久性:: 用几行代码将 Python 对象压缩并注释到 SQLite 中;然后按关键字按时间顺序检索它们,而无需任何 SQL。用于数据库存储无模式数据的最有用的“标准”模块。”

http://yserial.sourceforge.net

解决方案 12:

这是一个辅助类,您可以使用它来包装函数,使它们可 picklable。前面提到的注意事项marshal将适用,但我们会尽可能使用 pickle。不会在序列化过程中保留全局变量或闭包。

    class PicklableFunction:
        def __init__(self, fun):
            self._fun = fun

        def __call__(self, *args, **kwargs):
            return self._fun(*args, **kwargs)

        def __getstate__(self):
            try:
                return pickle.dumps(self._fun)
            except Exception:
                return marshal.dumps((self._fun.__code__, self._fun.__name__))

        def __setstate__(self, state):
            try:
                self._fun = pickle.loads(state)
            except Exception:
                code, name = marshal.loads(state)
                self._fun = types.FunctionType(code, {}, name)
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2974  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1836  
  PLM(产品生命周期管理)系统在企业的产品研发、生产与管理过程中扮演着至关重要的角色。然而,在实际运行中,资源冲突是经常会遇到的难题。资源冲突可能导致项目进度延迟、成本增加以及产品质量下降等一系列问题,严重影响企业的效益与竞争力。因此,如何有效应对PLM系统中的资源冲突,成为众多企业关注的焦点。接下来,我们将详细探讨5...
plm项目管理系统   47  
  敏捷项目管理与产品生命周期管理(PLM)的融合,正成为企业在复杂多变的市场环境中提升研发效率、增强竞争力的关键举措。随着技术的飞速发展和市场需求的快速更迭,传统的研发流程面临着诸多挑战,而将敏捷项目管理理念融入PLM,有望在2025年实现研发流程的深度优化,为企业创造更大的价值。理解敏捷项目管理与PLM的核心概念敏捷项...
plm项目   47  
  模块化设计在现代产品开发中扮演着至关重要的角色,它能够提升产品开发效率、降低成本、增强产品的可维护性与可扩展性。而产品生命周期管理(PLM)系统作为整合产品全生命周期信息的关键平台,对模块化设计有着强大的支持能力。随着技术的不断发展,到 2025 年,PLM 系统在支持模块化设计方面将有一系列令人瞩目的技术实践。数字化...
plm软件   48  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用