初始化PyObject而不调用__init__

时间:2018-07-09 01:29:15

标签: python c cpython python-internals

我有一个包装类,如下面的示例,是用Python编写的。

class Foo:
    def __init__(self, bar=None):
        if bar:
            self._bar = bar
        else:
            self._bar = CreateBarObject("value") 

我通过Python C API创建实例

// c++ pseudo code for convenience

auto obj = PyObject_CallObject(Foo) 
auto bar = CreateBarObject("another_value");
PyObject_SetAttrString(obj, "_bar", bar)

从代码中可以看到,创建实例创建新的Foo.__init__对象的实例将被调用bar。但是我想绕开这种“繁重的”操作。那么,创建Foo实例的任何安全方法都可以使我可以通过Python C API设置self._bar吗?有什么想法吗?

2 个答案:

答案 0 :(得分:2)

您应该能够直接调用Foo中的the tp_new(相当于在Python层上调用Foo.__new__)。这将执行分配和C级的“强制初始化”工作,而没有tp_init / __init__的“可选初始化”工作。与pickle用于创建类型实例而不初始化它们的策略相同(因此,可以根据需要通过__setstate__或直接填充__dict__来填充它们。)

假设Foo是C级PyTypeObject*,则应采取以下措施:

auto emptytup = PyTuple_New(0);  /* AFAICT, the args tuple is mandatory, but kwargs is optional */
/* Error check for PyTuple_New failure */
auto obj = Foo->tp_new(Foo, emptytup, NULL);
Py_DECREF(emptytup);
/* Error check for new fail */
auto bar = CreateBarObject("another_value");
PyObject_SetAttrString(obj, "_bar", bar)

答案 1 :(得分:-1)

设置self.bar一个属性,该属性在首次需要时创建实例。

class Foo:

    def __init__(self, bar=None):
        self._bar = bar

    @property
    def bar(self):
        if self._bar is None:
            self._bar = CreateBarObject(...)
        return self._bar

该实例完全正常运行。实例的bar属性将在第一次需要时创建Bar对象。或者,您可以在此之前通过C API设置_bar,而将使用它。或者,您可以在实例化类时传入现有的Bar对象。您的选择。