c++ - 将 pickle 添加到用 C++ 编写的 Python 扩展

标签 c++ python c pickle

我用 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/

相关文章:

c++ - 绘图时MFC中的问题

python - 如何将 excel 转换为 python (tkinter)

python - 使用 PyHive 和 SqlAlchemy 创建表

c++ - `sqlite3` 忽略 `sqlite3_busy_timeout` 吗?

c++ - 如何在缓冲区中读取和写入多个对象(或任何数据)?

c++ - 我的 OpenGL 应用程序适用于 ATI,但不适用于 nNVIDIA pc

c++ - 模板初始化:

python - 尽管有制表符或空格,如何检查字符串是否在行首?

c - 如何从 srand(time(0)) 知道 secret 数字

c++ - 我怎样才能有效地洗牌?