唯一正确的方法是让两个应用程序使用定义Prime
类的任何模块的完全相同的版本,可在完全相同的限定名称下导入。至于什么可以腌制和解封?解释:
... 函数(内置和用户定义的)由“完全限定”的名称引用而不是值进行腌制。这意味着只有函数名和定义函数的模块的名称被腌制。函数的代码和它的任何函数属性都没有被腌制。因此,定义模块必须在 unpickling 环境中是可导入的,并且模块必须包含命名对象,否则将引发异常。
换句话说,当您Prime
在第二个应用程序中取消选择一个对象时,它将是第二个应用程序版本的Prime
类的实例,即使它来自第一个应用程序。
更一般地说,酸洗旨在序列化要在同一应用程序中读回的数据,或者至少在共享所有相关代码的非常紧密耦合的应用程序中。如果您想要更多解耦的交换机制,请考虑 JSON 或 YAML。
但是,假设您知道所有这些,并且出于某种原因确实想要腌制方法实现。你能做到吗?
你当然可以。这将是很多工作,而且有点hacky。由于您正在尝试做一些 Python 明确尝试不做的事情,所以您不得不期待这一点。
首先,您需要编写一个代码选择器来传递足够的信息,以便您可以types.CodeType
使用它调用构造函数。那是实现细节与语言的深层部分之间的界限,所以你可以看到构造函数参数的唯一地方是help
在交互式控制台上输入,而你可以知道这些参数意味着什么的唯一方法是查看文档中的表格inspect
并猜测哪个参数与成员一起使用。(这很简单——<code>argcount 与co_argcount
等一起使用。)
您会注意到其中一些code
成员实际上可能没有意义。例如,您是否真的想通过co_filename
,并且co_firstlineno
如果接收方不打算在文件系统中的同一路径上拥有这些文件?(这将导致错误生成回溯,而不仅仅是没有源信息的回溯。)
无论如何,pickler 只是创建并腌制你想要的任何成员的元组,而 unpickler 则相反。但是您可能想在其中填充sys.version_info
或其他一些标记,这样您就不会尝试解开您无法运行的字节码。(查看 .pyc 文件的工作原理以了解详细信息。)
接下来你必须对函数类型做同样的事情——这当然会code
为它们的代码对象调用pickler。
所以,现在你有了可以pickle和unpickle函数的代码(包括它的代码)。这对你有什么好处?
当您编写Primes.__getstate__
和/或Primes.__reduce__
时,您可以覆盖正常的酸洗机制,以将func
方法的实现视为对象状态的一部分。
如果你真的想要,你可以腌制元类,所以func
方法可以作为类状态的一部分腌制,这意味着你最终会在类字典上得到一个普通的实例方法描述符,而不是塞进一个绑定的方法对象的字典。但是,如果您可以同时拥有“本地”对象和未腌制Primes
对象,那将无法正常工作。