【问题标题】:Python instance method in CC中的Python实例方法
【发布时间】:2009-12-23 18:25:06
【问题描述】:

考虑以下 Python (3.x) 代码:

class Foo(object):
    def bar(self):
        pass
foo = Foo()

如何用 C 编写相同的功能?

我的意思是,如何使用 C 中的方法创建对象?然后从中创建一个实例?

编辑: 哦对不起!我的意思是通过 Python C API 实现相同的功能。如何通过其 C API 创建 Python 方法? 比如:

PyObject *Foo = ?????;
PyMethod??? *bar = ????;

【问题讨论】:

  • 结构可以包含指向函数的指针。结构几乎就像一个类。
  • 我认为大多数人都误解了这个问题(或者我可能是),你可能想澄清一下。我理解,问题是如何使用 C Python API 创建一个 python 类及其实例。我从未使用过 C API,但我很确定您只能创建函数,然后用 Python 编写类来访问这些函数。
  • 是的,完全正确!对于造成的混乱,我深表歉意!
  • 您可能刚刚记录了“答案删除最多的问题”,也可能没有。 ;)
  • @Jeffrey:您可以使用 C API 创建类。请记住:Python 的所有内置函数都是在 C API 中实现的。

标签: python c python-c-api


【解决方案1】:

这是一个简单的类(改编自 http://nedbatchelder.com/text/whirlext.html for 3.x):

#include "Python.h"
#include "structmember.h"

// The CountDict type.

typedef struct {
   PyObject_HEAD
   PyObject * dict;
   int count;
} CountDict;

static int
CountDict_init(CountDict *self, PyObject *args, PyObject *kwds)
{
   self->dict = PyDict_New();
   self->count = 0;
   return 0;
}

static void
CountDict_dealloc(CountDict *self)
{
   Py_XDECREF(self->dict);
   self->ob_type->tp_free((PyObject*)self);
}

static PyObject *
CountDict_set(CountDict *self, PyObject *args)
{
   const char *key;
   PyObject *value;

   if (!PyArg_ParseTuple(args, "sO:set", &key, &value)) {
      return NULL;
   }

   if (PyDict_SetItemString(self->dict, key, value) < 0) {
      return NULL;
   }

   self->count++;

   return Py_BuildValue("i", self->count);
}

static PyMemberDef
CountDict_members[] = {
   { "dict",   T_OBJECT, offsetof(CountDict, dict), 0,
               "The dictionary of values collected so far." },

   { "count",  T_INT,    offsetof(CountDict, count), 0,
               "The number of times set() has been called." },

   { NULL }
};

static PyMethodDef
CountDict_methods[] = {
   { "set",    (PyCFunction) CountDict_set, METH_VARARGS,
               "Set a key and increment the count." },
   // typically there would be more here...

   { NULL }
};

static PyTypeObject
CountDictType = {
   PyObject_HEAD_INIT(NULL)
   0,                         /* ob_size */
   "CountDict",               /* tp_name */
   sizeof(CountDict),         /* tp_basicsize */
   0,                         /* tp_itemsize */
   (destructor)CountDict_dealloc, /* tp_dealloc */
   0,                         /* tp_print */
   0,                         /* tp_getattr */
   0,                         /* tp_setattr */
   0,                         /* tp_compare */
   0,                         /* tp_repr */
   0,                         /* tp_as_number */
   0,                         /* tp_as_sequence */
   0,                         /* tp_as_mapping */
   0,                         /* tp_hash */
   0,                         /* tp_call */
   0,                         /* tp_str */
   0,                         /* tp_getattro */
   0,                         /* tp_setattro */
   0,                         /* tp_as_buffer */
   Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags*/
   "CountDict object",        /* tp_doc */
   0,                         /* tp_traverse */
   0,                         /* tp_clear */
   0,                         /* tp_richcompare */
   0,                         /* tp_weaklistoffset */
   0,                         /* tp_iter */
   0,                         /* tp_iternext */
   CountDict_methods,         /* tp_methods */
   CountDict_members,         /* tp_members */
   0,                         /* tp_getset */
   0,                         /* tp_base */
   0,                         /* tp_dict */
   0,                         /* tp_descr_get */
   0,                         /* tp_descr_set */
   0,                         /* tp_dictoffset */
   (initproc)CountDict_init,  /* tp_init */
   0,                         /* tp_alloc */
   0,                         /* tp_new */
};

// Module definition

static PyModuleDef
moduledef = {
    PyModuleDef_HEAD_INIT,
    "countdict",
    MODULE_DOC,
    -1,
    NULL,       /* methods */
    NULL,
    NULL,       /* traverse */
    NULL,       /* clear */
    NULL
};


PyObject *
PyInit_countdict(void)
{
    PyObject * mod = PyModule_Create(&moduledef);
    if (mod == NULL) {
        return NULL;
    }

    CountDictType.tp_new = PyType_GenericNew;
    if (PyType_Ready(&CountDictType) < 0) {
        Py_DECREF(mod);
        return NULL;
    }

    Py_INCREF(&CountDictType);
    PyModule_AddObject(mod, "CountDict", (PyObject *)&CountDictType);

    return mod;
}

【讨论】:

  • 我真的需要创建一个新类型来创建一个简单的实例方法吗?我认为它更简单....
  • 我不知道没有实例的方法可以制作实例方法,并且需要一个类来制作实例。
  • 创建类型似乎相当复杂。我认为创建预定义类“对象”的实例会简单得多。但也许 Py3k 中的类型和类是一样的?
  • 在 Python 2.x 中,类也是类型(有些类型不是类,但我对细节有点模糊)。 C API 功能强大,但并不总是很方便。我觉得有点傻,“这是一个简单类”,然后粘贴了143行代码,但这就是野兽的本性。
【解决方案2】:

你不能! C 没有“类”,它只有structs。而struct 不能有代码(方法或函数)。

但是,您可以使用函数指针来伪造它:

/* struct object has 1 member, namely a pointer to a function */
struct object {
    int (*class)(void);
};

/* create a variable of type `struct object` and call it `new` */
struct object new;
/* make its `class` member point to the `rand()` function */
new.class = rand;

/* now call the "object method" */
new.class();

【讨论】:

    【解决方案3】:

    我建议你从示例源代码 here 开始——它是 Python 3 源代码的一部分,它的存在专门通过示例向你展示如何执行你需要的东西(以及其他一些东西)—— - 使用 C API 创建一个模块,在该模块中创建一个新类型,赋予该类型方法和属性。这基本上是源代码的第一部分,在Xxo_Type 的定义中达到高潮——然后您将获得如何定义各种函数的示例,一些您可能不关心的其他类型,最后是模块对象及其初始化(当然,您可以跳过大部分内容,但不能跳过模块对象及其初始化中导致感兴趣类型定义的部分;-)。

    您在研究和调整该源以适应您的特定需求时可能遇到的大多数问题在the docs 中都有很好的答案,尤其是在“对象实现支持”的section 中——当然您可以随时打开一个这里有一个新问题(最好是每个问题一个问题——一个包含许多实际问题的“问题”总是很麻烦!-)准确地显示你在做什么,你所期望的结果,以及你所看到的——你会得到一些答案,其中往往包括一些非常有用的答案;-)。

    【讨论】:

    • 该链接是关于创建新类型的,我认为可以只创建一个简单的 PyObject 并以某种方式添加一个可调用对象(方法)。但也许我没有完全理解——在 Python 3 中,类型和对象是一回事吗?
    • @Ecirh,不:所有类型都是对象,但并非所有对象都是类型。您可以将可调用属性添加到一些不是类型的对象(例如模块),但这些可调用属性不会是“方法”——它们通常是普通函数。如果您想要创建一个新的模块对象并为其添加一些功能,请这样说而不是特别提到“实例方法”!!!
    • 对不起,我很困惑。你是对的,我不想要精确的“实例方法”,我不知道可以通过“实例方法”以外的方式满足writer = PyObject_GetAttrString(f, "write");
    猜你喜欢
    • 1970-01-01
    • 2021-06-30
    • 2021-06-24
    • 1970-01-01
    • 2018-03-07
    • 1970-01-01
    • 1970-01-01
    • 2016-09-20
    • 1970-01-01
    相关资源
    最近更新 更多