我用 C 编写了一个 Python 扩展。它可以正常工作,没有问题。现在我想用它来 pickle 。从文档中我很困惑。我写了一个测试 __reduce__
函数作为“扩展”的建议:
http://docs.python.org/library/pickle.html#the-pickle-protocol
我想念的是“可调用对象”应该是什么。我已尝试使用 PyObject_Type(self)
的结果。这是“可调用的”并且基本上可以工作,但是当对象被解锁时它会调用 __init__
这给我带来了一些麻烦。
是否有任何标准方法可以让可调用对象仅调用 __new__
方法,避免类初始化?
最佳答案
如果您调用 __new__
并且您使用类型作为元类,如果 __new__
的结果是子类型,则将调用 __init__
你的类型。换句话说,假设你有一个 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__
并且您可以获得您想要的正在寻找。 (不要忘记提供 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__
接受它)并且只在第三个参数中提供一堆将直接更新 __dict__
的东西。如果您查看 Modules and Objects 目录中的 cpython 源代码,您会看到许多 __reduce__
的实现,所有这些都以这种方式工作。
关于c++ - 将 pickle 添加到用 C++ 编写的 Python 扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8706416/