Adding new python type : TypeError: can't set attributes of built-in/extension type
Adding new python type : TypeError: can't set attributes of built-in/extension type
下面 python-c 代码可以正确编译
#include <Python.h>
#include <structmember.h>
struct rangerr {
long min;
long max;
};
//Python type to represent rangerr
struct py_rangerr {
PyObject_HEAD
struct rangerr range;
};
// * get & set methods for py_rangerr
static PyObject * py_rangerr_min_get(struct py_rangerr *self) {
self->range.min = 1;
return PyLong_FromLong(self->range.min);
}
static PyObject * py_rangerr_min_set(struct py_rangerr *self) {
printf("Setter called");
self->range.min = 1;
}
static PyObject * py_rangerr_max_get(struct py_rangerr *self) {
self->range.max = 10;
return PyLong_FromLong(self->range.max);
}
//* GetSet method definition for py_rangerr
static PyGetSetDef py_rangerr_getset[] = {
{"min",(getter)py_rangerr_min_get, (setter)py_rangerr_min_set, "min",NULL},
{"max",(getter)py_rangerr_max_get, NULL, "max",NULL},
/* Sentinel */
{NULL},
};
/******************************************************************************
*/
static void py_rangerr_dealloc(struct py_rangerr *self) {
self->ob_type->tp_free((PyObject *)self);
}
static PyTypeObject py_rangerr_type = {
PyObject_HEAD_INIT(NULL)
.tp_name = "rangerr",
.tp_basicsize = sizeof(struct py_rangerr),
.tp_dealloc = (destructor) py_rangerr_dealloc,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_alloc = PyType_GenericAlloc,
.tp_doc = "rangerr",
.tp_getset = py_rangerr_getset,
};
void
initrangerr(void)
{
PyObject* mod;
mod = Py_InitModule3("rangerr", NULL, "An extension with a type.");
if (mod == NULL) {
return;
}
py_rangerr_type.tp_new = PyType_GenericNew;
if (PyType_Ready(&py_rangerr_type) < 0){
return;
}
Py_INCREF(&py_rangerr_type);
PyModule_AddObject(mod, "rangerr", (PyObject*)&py_rangerr_type);
}
但是当我尝试调用 set/get 方法时它会抛出以下错误:
>>> import rangerr as r
>>> r.rangerr.min
<attribute 'min' of 'rangerr' objects>
>>> r.rangerr.min=2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'rangerr'
>>> type(r.rangerr.min)
<type 'getset_descriptor'>
我需要添加类似 "PyMemberDef" 的内容吗?感谢您的任何指示或帮助。
不可能直接为参数设置默认值。您可以向模块添加一个函数,以将全局默认值设置为静态变量。
如果你只想初始化你的实例,你应该像
这样定义PyTypeObject.tp_init
static int py_rangerr_init(struct py_rangerr *self, PyObject *args, PyObject *kwds) {
static char *kwlist[] = {"min", "max", NULL};
int min = 0, max = 1;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwlist, &min, &max))
return -1;
self->range.min = min;
self->range.max = max;
return 0;
}
static PyTypeObject py_rangerr_type = {
PyObject_HEAD_INIT(NULL)
[...]
.tp_init = (initproc) py_rangerr_init,
};
如果您不为 min
或 max
提供值,将使用行 int min = 0, max = 1;
中的默认值。
关于您关于 PyMemberDef
用法的问题,对于像 int
这样的类型,使用 PyTypeObject.tp_members
可能更容易重复,也更不容易出错PyTypeObject.tp_getset
.
除了setter的typedef是:
typedef int (*setter)(PyObject *, PyObject *, void *);
下面 python-c 代码可以正确编译
#include <Python.h>
#include <structmember.h>
struct rangerr {
long min;
long max;
};
//Python type to represent rangerr
struct py_rangerr {
PyObject_HEAD
struct rangerr range;
};
// * get & set methods for py_rangerr
static PyObject * py_rangerr_min_get(struct py_rangerr *self) {
self->range.min = 1;
return PyLong_FromLong(self->range.min);
}
static PyObject * py_rangerr_min_set(struct py_rangerr *self) {
printf("Setter called");
self->range.min = 1;
}
static PyObject * py_rangerr_max_get(struct py_rangerr *self) {
self->range.max = 10;
return PyLong_FromLong(self->range.max);
}
//* GetSet method definition for py_rangerr
static PyGetSetDef py_rangerr_getset[] = {
{"min",(getter)py_rangerr_min_get, (setter)py_rangerr_min_set, "min",NULL},
{"max",(getter)py_rangerr_max_get, NULL, "max",NULL},
/* Sentinel */
{NULL},
};
/******************************************************************************
*/
static void py_rangerr_dealloc(struct py_rangerr *self) {
self->ob_type->tp_free((PyObject *)self);
}
static PyTypeObject py_rangerr_type = {
PyObject_HEAD_INIT(NULL)
.tp_name = "rangerr",
.tp_basicsize = sizeof(struct py_rangerr),
.tp_dealloc = (destructor) py_rangerr_dealloc,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_alloc = PyType_GenericAlloc,
.tp_doc = "rangerr",
.tp_getset = py_rangerr_getset,
};
void
initrangerr(void)
{
PyObject* mod;
mod = Py_InitModule3("rangerr", NULL, "An extension with a type.");
if (mod == NULL) {
return;
}
py_rangerr_type.tp_new = PyType_GenericNew;
if (PyType_Ready(&py_rangerr_type) < 0){
return;
}
Py_INCREF(&py_rangerr_type);
PyModule_AddObject(mod, "rangerr", (PyObject*)&py_rangerr_type);
}
但是当我尝试调用 set/get 方法时它会抛出以下错误:
>>> import rangerr as r
>>> r.rangerr.min
<attribute 'min' of 'rangerr' objects>
>>> r.rangerr.min=2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'rangerr'
>>> type(r.rangerr.min)
<type 'getset_descriptor'>
我需要添加类似 "PyMemberDef" 的内容吗?感谢您的任何指示或帮助。
不可能直接为参数设置默认值。您可以向模块添加一个函数,以将全局默认值设置为静态变量。
如果你只想初始化你的实例,你应该像
这样定义PyTypeObject.tp_init
static int py_rangerr_init(struct py_rangerr *self, PyObject *args, PyObject *kwds) {
static char *kwlist[] = {"min", "max", NULL};
int min = 0, max = 1;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwlist, &min, &max))
return -1;
self->range.min = min;
self->range.max = max;
return 0;
}
static PyTypeObject py_rangerr_type = {
PyObject_HEAD_INIT(NULL)
[...]
.tp_init = (initproc) py_rangerr_init,
};
如果您不为 min
或 max
提供值,将使用行 int min = 0, max = 1;
中的默认值。
关于您关于 PyMemberDef
用法的问题,对于像 int
这样的类型,使用 PyTypeObject.tp_members
可能更容易重复,也更不容易出错PyTypeObject.tp_getset
.
除了setter的typedef是:
typedef int (*setter)(PyObject *, PyObject *, void *);