jjzjj

Python 的 __reduce__/copy_reg 语义和有状态的 unpickler

coder 2023-08-24 原文

我想为属于我的扩展库的对象实现 pickle 支持。有一个在启动时初始化的类服务的全局实例。所有这些对象都是作为某些服务方法调用的结果而产生的,并且本质上属于它。服务知道如何将它们序列化为二进制缓冲区以及如何将缓冲区反序列化回对象。

看来 Python 的 __reduce__ 应该符合我的目的 - 实现 pickling 支持。我开始实现一个并意识到 unpickler 存在问题(元组的第一个元素预计由 __ reduce__ 返回)。此 unpickle 函数需要服务实例才能将输入缓冲区转换为对象。下面是一些伪代码来说明这个问题:

class Service(object):
   ...
   def pickleObject(self,obj):
      # do serialization here and return buffer
      ...

   def unpickleObject(self,buffer):
      # do deserialization here and return new Object
      ...

class Object(object):
    ...
    def __reduce__(self):
        return self.service().unpickleObject, (self.service().pickleObject(self),)

注意元组中的第一个元素。 Python pickler 不喜欢它:它说它是 instancemethod 并且不能被 pickle。显然,pickler 试图将例程存储到输出中,并且需要服务实例和函数名称,但这不是我想要发生的。我不想(而且真的不能:服务不可挑选)将服务与所有对象一起存储。我希望在调用 pickle.load 之前创建服务实例,并以某种方式在 unpickling 期间使用该实例。

这里是我通过 copy_reg 模块来的。它再次出现,因为它应该可以解决我的问题。该模块允许动态注册每种类型的 pickler 和 unpickler 例程,这些例程应该稍后用于这种类型的对象。所以我将此注册添加到服务构造中:

class Service(object):
  ...
  def __init__(self):
      ...
      import copy_reg
      copy_reg( mymodule.Object, self.pickleObject, self.unpickleObject )

self.unpickleObject 现在是一个绑定(bind)方法,将服务作为第一个参数,缓冲区作为第二个参数。 self.pickleObject 也是将服务和对象 pickle 的绑定(bind)方法。 copy_reg 要求 pickleObject 例程应遵循 reducer 语义并返回与以前类似的元组。问题又来了:元组的第一个元素应该返回什么??

class Service(object):
  ...
  def pickleObject(self,obj):
      ...
      return self.unpickleObject, (self.serialize(obj),)

在这种形式中,pickle 再次提示它无法 pickle instancemethod。我试过无 - 它也不喜欢它。我在那里放了一些虚拟函数。这有效 - 这意味着序列化阶段进行得很好,但在 unpickling 期间它调用这个虚拟函数而不是 unpickler 我在服务构造函数中注册了 mymodule.Object 类型。

所以现在我很茫然。很抱歉解释很长:我不知道如何用几行来问这个问题。我可以这样总结我的问题:

  1. 如果我希望独立注册一个,为什么 copy_reg 语义要求我从 pickleObject 返回 unpickler 例程?
  2. 有什么理由更喜欢 copy_reg.constructor 接口(interface)来注册 unpickler 例程?
  3. 如何制作 pickle 以使用我注册的 unpickler 而不是流中的 unpickler?
  4. 我应该将元组中的第一个元素作为 pickleObject 结果值返回什么?是否有“正确”的值?
  5. 我是否正确处理了整件事?是否有不同/更简单的解决方案?

最佳答案

首先,copy_reg 模块在这里不太可能帮到你:它主要是一种向没有该功能的类添加类似 __reduce__ 功能的方法方法而不是提供任何特殊能力(例如,如果你想从一些本身不支持它的库中挑选对象)。

__reduce__ 返回的可调用对象需要位于对象要被解封的环境中,因此实例方法并不合适。如 Pickle documentation 中所述:

In the unpickling environment this object must be either a class, a callable registered as a “safe constructor” (see below), or it must have an attribute __safe_for_unpickling__ with a true value.

所以如果你定义一个函数(不是方法)如下:

def _unpickle_service_object(buffer):
    # Grab the global service object, however that is accomplished
    service = get_global_service_object()
    return service.unpickleObject(buffer)

_unpickle_service_object.__safe_for_unpickling__ = True

您现在可以在 __reduce__ 方法的返回值中使用此 _unpickle_service_object 函数,以便您的对象链接到新环境的全局 Service未 pickle 时的对象。

关于Python 的 __reduce__/copy_reg 语义和有状态的 unpickler,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12065657/

有关Python 的 __reduce__/copy_reg 语义和有状态的 unpickler的更多相关文章

  1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  2. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  3. ruby-on-rails - 跳过状态机方法的所有验证 - 2

    当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested

  4. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  5. ruby - 字符串文字中的转义状态作为 `String#tr` 的参数 - 2

    对于作为String#tr参数的单引号字符串文字中反斜杠的转义状态,我觉得有些神秘。你能解释一下下面三个例子之间的对比吗?我特别不明白第二个。为了避免复杂化,我在这里使用了'd',在双引号中转义时不会改变含义("\d"="d")。'\\'.tr('\\','x')#=>"x"'\\'.tr('\\d','x')#=>"\\"'\\'.tr('\\\d','x')#=>"x" 最佳答案 在tr中转义tr的第一个参数非常类似于正则表达式中的括号字符分组。您可以在表达式的开头使用^来否定匹配(替换任何不匹配的内容)并使用例如a-f来匹配一

  6. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  7. Python 相当于 Perl/Ruby ||= - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。

  8. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  9. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  10. python - 如何读取 MIDI 文件、更改其乐器并将其写回? - 2

    我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的

随机推荐