我在C中编写了一个Python扩展。它有效,没问题。现在我想用它来泡菜。从文档我很困惑。我在这里为“扩展”编写了一个测试__reduce__
函数:
http://docs.python.org/library/pickle.html#the-pickle-protocol
我想念的是“可调用对象”应该是什么。我试过了PyObject_Type(self)
的结果。这是“可调用的”并且基本上可以工作,但是当对象被打开时,它会调用__init__
,这给我带来了一些麻烦。
有没有标准的方法来调用只调用__new__
方法的callable,避免类初始化?
答案 0 :(得分:2)
如果您致电__new__
,并且您使用类型作为元类,则__init__
的结果将是__new__
的类型的子类型。换句话说,让我们说你有一个Foo课。如果您调用PyObject_Type(self)
的结果,则与调用Foo()
相同。这意味着将调用Foo。__new__
,如果返回值是Foo的子类型,则将调用__init__
。
深入挖掘,当你调用Foo()时,它真正调用type_call(在typeobject.c中),这就是tp_new后跟tp_init的内容。如果您直接提供对象的新函数(例如Foo_new()而不是PyObject_Type(self)),那么您在不调用__new__
的情况下调用__init__
并且可以获得您的&{ #39;重新寻找。 (别忘了提供Foo作为__new__
的论据。)
因此,要最终回答您的问题,您只需致电Foo.__new__(Foo, ...)
即可。这里有一些代码可以帮助您查找。
class Foo(object):
def __new__(cls):
return super(Foo, cls).__new__(cls)
def __init__(self):
print "__init__"
def __reduce__(self):
return (Foo.__new__, (Foo, ))
print "one"
x = Foo() # prints __init__
print "two"
y = Foo.__new__(Foo) # does not print __init__
print "three"
import pickle
p = pickle.dumps(Foo)
z = pickle.loads(p) # does not print __init__
顺便说一句,当我试图弄清楚这一点时,我发现在几乎所有情况下,我实际上可以实现我的代码并允许调用__init__
。我的错误源于这样一个事实:我没有把那些进入__reduce__
元组的第三个参数的东西分开。为第二个参数提供任何内容都是完全可以的(假设__init__
接受了这一点)并在第3个参数中提供了一堆将直接更新__dict__
的内容。如果您查看模块和对象目录中的cpython源代码,您将看到__reduce__
的许多实现,所有这些都以这种方式工作。