2013-07-02 24 views
1

正如我所理解的,您可以在文件和项目之间发送物体,只要这些物体都存在于两个名称空间中即可。我有两个应用程序,这将传递一个Prime对象。更改腌渍物体的功能

class Prime(): 
    def __init__(self): 
     self.a = 1 
    def func(self): 
     print(self.a) 

这两个应用程序都以上面的素数版本开始。但第一个应用程序将不得不改变Prime的功能,例如func将会打印(“hello world”)。然后,第二个应用程序将收到总理的第一次的版本通过泡菜和使用这样的:

Second.py:

i = Prime 
i.func() 
with open("temp.txt", "r") as text: 
    o = pickle.load(text) 
    o.func() 

输出:

1 
hello world 

我的2部分的问题这是。如果第二个应用程序在其名称空间中只有原始版本的Prime,那么只要函数名称没有更改,它就可以使用第一个应用程序。如果是的话,我该如何去改变Prime.func的功能?

+1

首先,你的意思是'我= Prime()'? – abarnert

+0

其次,你真的不能使用'pickle'在不同的应用程序之间发送具有不同模块和类名的相同名称的对象,而没有很多诡异的解决方法。你是否特别要问如何为你的特定案例做这些黑客行为?即使你知道这通常是一个坏主意,因为你确定在这种情况下它不是? – abarnert

+1

最后,通常'pickle'永远不会真正地腌制函数对象,只是[完全限定引用它们的名字](http://docs.python。组织/ 2 /库/ pickle.html#什么,可待腌-和拆封)。解决这个问题的唯一方法是实现你自己的'__reduce__'和朋友,他们会做一些事情,像pickle'co_code'和其他需要从另一边重新构建代码和函数的信息(并检查它是否适合Python版本,作为.pyc文件)。如果这对你来说听起来像是希腊语,你甚至不应该考虑这一点。 – abarnert

回答

1

唯一办法做到这一点是让这​​两个应用程序使用的任何模块定义了Prime类,在完全相同的限定名导入的版本完全相同。由于What can be pickled and unpickled?解释为:

...函数(内置的和用户定义的)由“完全限定”名称引用而不是按值赋值。这意味着只有函数名称被腌渍,以及定义该函数的模块的名称。该函数的代码及其任何函数属性都不会被腌制。因此,定义模块必须可以在取消环境中导入,并且模块必须包含指定的对象,否则将引发异常。

换句话说,当你在第二个应用程序unpickle一个Prime对象,这将是第二个应用程序的版本Prime类的实例,即使从第一个应用程序来。


更一般地,酸洗被设计为序列数据要被读回在同一应用程序,或至少在一个非常紧密耦合的应用程序共享所有相关代码。如果您想要更多的分离交换机制,请考虑使用JSON或YAML。


但是,假设你知道了这一切,而你确实想腌出于某种原因的方法实现。你能做到吗?

当然可以。这只是一个很大的工作,而且有点冒险。既然你正在试图做一些Python显式地不想做的事情,那么你必须期待这一点。

首先,你需要编写一个代码pickler来传递足够的信息,你可以用它来调用types.CodeType的构造函数。这是在实施细节与只是语言的一个深层部分,所以唯一可以看到构造函数参数的地方是在交互式控制台上键入help,并且唯一可以通过查看the table in the inspect docs并且猜测哪个参数发生变化来告诉那些参数意思是的方法与成员一起。 (这很简单 - argcountco_argcount等)

你会注意到,一些code成员可能实际上没有意义。例如,如果接收器不打算将这些文件放在文件系统的相同路径中,是否真的想通过co_filenameco_firstlineno? (这会导致产生回溯的错误,而不仅仅是没有源信息的回溯。)

无论如何,pickler只是创建并腌制你想要的任何成员的元组,而unpickler则会相反。但是你可能想在这里填入sys.version_info或其他标记,所以你不要试图解除字节码,你不能运行。 (看看.pyc文件如何处理细节。)

接下来,你必须对函数类型做同样的事情 - 当然,它会为其代码对象调用code pickler。

所以,现在你有代码可以pickle和unickle一个函数(包括它的代码)。你有什么好处?

当您编写您的Primes.__getstate__和/或Primes.__reduce__时,您可以覆盖正常的酸洗机制,以将func方法的实现视为对象状态的一部分。

如果你真的愿意,你可以泡制元类,所以func方法可以腌制作为类的状态,而不是,这意味着你会在类字典正常的实例方法描述符结束的一部分而不是绑定到对象字典中的绑定方法。但如果你可以同时拥有“本地”和未取消的对象Primes,那么这将不起作用。

1

第一个问题:不。这不是酸洗的工作原理。 但是对于你的第二个问题,有一个简单的方法来做到这一点。 您可以使用一个名为marshal的模块,它允许您序列化函数的代码,并且可以将其与某个对象的副本一起存储。

import marshal 
import pickle 
class A: 
    def __init__(self): 
     self.a = 1 
    def func(self): 
     print self.a 
firstA = A() 
s = pickle.dumps(firstA) 
sf = marshal.dumps(A.func.func_code) 

别的地方,你有不同的A类:

class A: 
    def __init__(self): 
     self.a = 2 
    def func(self): 
     print "Hello world" 

当加载刚对象,它仍然会使用不正确的功能:

secondA = pickle.loads(s) 
secondA.func() #prints "Hello world" 

然后,您可以使用函数代码的值调用正确的函数:

#change the function to match what was stored 
secondA.func.__func__.func_code = marshal.loads(sf) 
secondA.func() #prints 1