📄 classobject.c
字号:
/* Portions Copyright (c) 2005 Nokia Corporation */
/* Class object implementation */
#include "Python.h"
#include "structmember.h"
#define TP_DESCR_GET(t) \
(PyType_HasFeature(t, Py_TPFLAGS_HAVE_CLASS) ? (t)->tp_descr_get : NULL)
/* Forward */
static PyObject *class_lookup(PyClassObject *, PyObject *,
PyClassObject **);
static PyObject *instance_getattr1(PyInstanceObject *, PyObject *);
static PyObject *instance_getattr2(PyInstanceObject *, PyObject *);
#ifndef SYMBIAN
static PyObject *getattrstr, *setattrstr, *delattrstr;
#else
#define getattrstr (pyglobals->getattrstr)
#define setattrstr (pyglobals->setattrstr)
#define delattrstr (pyglobals->delattrstr)
#endif
DL_EXPORT(PyObject *)
PyClass_New(PyObject *bases, PyObject *dict, PyObject *name)
/* bases is NULL or tuple of classobjects! */
{
PyClassObject *op, *dummy;
#ifndef SYMBIAN
static PyObject *docstr, *modstr, *namestr;
#else
#define docstr (pyglobals->docstr)
#define modstr (pyglobals->modstr)
#define namestr (pyglobals->classobject_namestr)
SPy_Python_globals* pyglobals = PYTHON_GLOBALS; // avoid TLS reads
#endif
if (docstr == NULL) {
docstr= PyString_InternFromString("__doc__");
if (docstr == NULL)
return NULL;
}
if (modstr == NULL) {
modstr= PyString_InternFromString("__module__");
if (modstr == NULL)
return NULL;
}
if (namestr == NULL) {
namestr= PyString_InternFromString("__name__");
if (namestr == NULL)
return NULL;
}
if (name == NULL || !PyString_Check(name)) {
PyErr_SetString(PyExc_TypeError,
"PyClass_New: name must be a string");
return NULL;
}
if (dict == NULL || !PyDict_Check(dict)) {
PyErr_SetString(PyExc_TypeError,
"PyClass_New: dict must be a dictionary");
return NULL;
}
if (PyDict_GetItem(dict, docstr) == NULL) {
if (PyDict_SetItem(dict, docstr, Py_None) < 0)
return NULL;
}
if (PyDict_GetItem(dict, modstr) == NULL) {
PyObject *globals = PyEval_GetGlobals();
if (globals != NULL) {
PyObject *modname = PyDict_GetItem(globals, namestr);
if (modname != NULL) {
if (PyDict_SetItem(dict, modstr, modname) < 0)
return NULL;
}
}
}
if (bases == NULL) {
bases = PyTuple_New(0);
if (bases == NULL)
return NULL;
}
else {
int i, n;
PyObject *base;
if (!PyTuple_Check(bases)) {
PyErr_SetString(PyExc_TypeError,
"PyClass_New: bases must be a tuple");
return NULL;
}
n = PyTuple_Size(bases);
for (i = 0; i < n; i++) {
base = PyTuple_GET_ITEM(bases, i);
if (!PyClass_Check(base)) {
if (PyCallable_Check(
(PyObject *) base->ob_type))
return PyObject_CallFunction(
(PyObject *) base->ob_type,
"OOO",
name,
bases,
dict);
PyErr_SetString(PyExc_TypeError,
"PyClass_New: base must be a class");
return NULL;
}
}
Py_INCREF(bases);
}
op = PyObject_GC_New(PyClassObject, &PyClass_Type);
if (op == NULL) {
Py_DECREF(bases);
return NULL;
}
op->cl_bases = bases;
Py_INCREF(dict);
op->cl_dict = dict;
Py_XINCREF(name);
op->cl_name = name;
if (getattrstr == NULL) {
getattrstr = PyString_InternFromString("__getattr__");
setattrstr = PyString_InternFromString("__setattr__");
delattrstr = PyString_InternFromString("__delattr__");
}
op->cl_getattr = class_lookup(op, getattrstr, &dummy);
op->cl_setattr = class_lookup(op, setattrstr, &dummy);
op->cl_delattr = class_lookup(op, delattrstr, &dummy);
Py_XINCREF(op->cl_getattr);
Py_XINCREF(op->cl_setattr);
Py_XINCREF(op->cl_delattr);
_PyObject_GC_TRACK(op);
return (PyObject *) op;
}
DL_EXPORT(PyObject *)
PyMethod_Function(PyObject *im)
{
if (!PyMethod_Check(im)) {
PyErr_BadInternalCall();
return NULL;
}
return ((PyMethodObject *)im)->im_func;
}
DL_EXPORT(PyObject *)
PyMethod_Self(PyObject *im)
{
if (!PyMethod_Check(im)) {
PyErr_BadInternalCall();
return NULL;
}
return ((PyMethodObject *)im)->im_self;
}
DL_EXPORT(PyObject *)
PyMethod_Class(PyObject *im)
{
if (!PyMethod_Check(im)) {
PyErr_BadInternalCall();
return NULL;
}
return ((PyMethodObject *)im)->im_class;
}
static PyObject *
class_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *name, *bases, *dict;
static const char *const kwlist[] = {"name", "bases", "dict", 0};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "SOO", kwlist,
&name, &bases, &dict))
return NULL;
return PyClass_New(bases, dict, name);
}
/* Class methods */
static void
class_dealloc(PyClassObject *op)
{
_PyObject_GC_UNTRACK(op);
Py_DECREF(op->cl_bases);
Py_DECREF(op->cl_dict);
Py_XDECREF(op->cl_name);
Py_XDECREF(op->cl_getattr);
Py_XDECREF(op->cl_setattr);
Py_XDECREF(op->cl_delattr);
PyObject_GC_Del(op);
}
static PyObject *
class_lookup(PyClassObject *cp, PyObject *name, PyClassObject **pclass)
{
int i, n;
PyObject *value = PyDict_GetItem(cp->cl_dict, name);
if (value != NULL) {
*pclass = cp;
return value;
}
n = PyTuple_Size(cp->cl_bases);
for (i = 0; i < n; i++) {
/* XXX What if one of the bases is not a class? */
PyObject *v = class_lookup(
(PyClassObject *)
PyTuple_GetItem(cp->cl_bases, i), name, pclass);
if (v != NULL)
return v;
}
return NULL;
}
static PyObject *
class_getattr(register PyClassObject *op, PyObject *name)
{
register PyObject *v;
register char *sname = PyString_AsString(name);
PyClassObject *class;
descrgetfunc f;
if (sname[0] == '_' && sname[1] == '_') {
if (strcmp(sname, "__dict__") == 0) {
if (PyEval_GetRestricted()) {
PyErr_SetString(PyExc_RuntimeError,
"class.__dict__ not accessible in restricted mode");
return NULL;
}
Py_INCREF(op->cl_dict);
return op->cl_dict;
}
if (strcmp(sname, "__bases__") == 0) {
Py_INCREF(op->cl_bases);
return op->cl_bases;
}
if (strcmp(sname, "__name__") == 0) {
if (op->cl_name == NULL)
v = Py_None;
else
v = op->cl_name;
Py_INCREF(v);
return v;
}
}
v = class_lookup(op, name, &class);
if (v == NULL) {
PyErr_Format(PyExc_AttributeError,
"class %.50s has no attribute '%.400s'",
PyString_AS_STRING(op->cl_name), sname);
return NULL;
}
f = TP_DESCR_GET(v->ob_type);
if (f == NULL)
Py_INCREF(v);
else
v = f(v, (PyObject *)NULL, (PyObject *)op);
return v;
}
static void
set_slot(PyObject **slot, PyObject *v)
{
PyObject *temp = *slot;
Py_XINCREF(v);
*slot = v;
Py_XDECREF(temp);
}
static void
set_attr_slots(PyClassObject *c)
{
PyClassObject *dummy;
#ifdef SYMBIAN
SPy_Python_globals* pyglobals = PYTHON_GLOBALS; // avoid TLS reads
#endif
set_slot(&c->cl_getattr, class_lookup(c, getattrstr, &dummy));
set_slot(&c->cl_setattr, class_lookup(c, setattrstr, &dummy));
set_slot(&c->cl_delattr, class_lookup(c, delattrstr, &dummy));
}
static char *
set_dict(PyClassObject *c, PyObject *v)
{
if (v == NULL || !PyDict_Check(v))
return "__dict__ must be a dictionary object";
set_slot(&c->cl_dict, v);
set_attr_slots(c);
return "";
}
static char *
set_bases(PyClassObject *c, PyObject *v)
{
int i, n;
if (v == NULL || !PyTuple_Check(v))
return "__bases__ must be a tuple object";
n = PyTuple_Size(v);
for (i = 0; i < n; i++) {
PyObject *x = PyTuple_GET_ITEM(v, i);
if (!PyClass_Check(x))
return "__bases__ items must be classes";
if (PyClass_IsSubclass(x, (PyObject *)c))
return "a __bases__ item causes an inheritance cycle";
}
set_slot(&c->cl_bases, v);
set_attr_slots(c);
return "";
}
static char *
set_name(PyClassObject *c, PyObject *v)
{
if (v == NULL || !PyString_Check(v))
return "__name__ must be a string object";
if (strlen(PyString_AS_STRING(v)) != (size_t)PyString_GET_SIZE(v))
return "__name__ must not contain null bytes";
set_slot(&c->cl_name, v);
return "";
}
static int
class_setattr(PyClassObject *op, PyObject *name, PyObject *v)
{
char *sname;
if (PyEval_GetRestricted()) {
PyErr_SetString(PyExc_RuntimeError,
"classes are read-only in restricted mode");
return -1;
}
sname = PyString_AsString(name);
if (sname[0] == '_' && sname[1] == '_') {
int n = PyString_Size(name);
if (sname[n-1] == '_' && sname[n-2] == '_') {
char *err = NULL;
if (strcmp(sname, "__dict__") == 0)
err = set_dict(op, v);
else if (strcmp(sname, "__bases__") == 0)
err = set_bases(op, v);
else if (strcmp(sname, "__name__") == 0)
err = set_name(op, v);
else if (strcmp(sname, "__getattr__") == 0)
set_slot(&op->cl_getattr, v);
else if (strcmp(sname, "__setattr__") == 0)
set_slot(&op->cl_setattr, v);
else if (strcmp(sname, "__delattr__") == 0)
set_slot(&op->cl_delattr, v);
/* For the last three, we fall through to update the
dictionary as well. */
if (err != NULL) {
if (*err == '\0')
return 0;
PyErr_SetString(PyExc_TypeError, err);
return -1;
}
}
}
if (v == NULL) {
int rv = PyDict_DelItem(op->cl_dict, name);
if (rv < 0)
PyErr_Format(PyExc_AttributeError,
"class %.50s has no attribute '%.400s'",
PyString_AS_STRING(op->cl_name), sname);
return rv;
}
else
return PyDict_SetItem(op->cl_dict, name, v);
}
static PyObject *
class_repr(PyClassObject *op)
{
PyObject *mod = PyDict_GetItemString(op->cl_dict, "__module__");
char *name;
if (op->cl_name == NULL || !PyString_Check(op->cl_name))
name = "?";
else
name = PyString_AsString(op->cl_name);
if (mod == NULL || !PyString_Check(mod))
return PyString_FromFormat("<class ?.%s at %p>", name, op);
else
return PyString_FromFormat("<class %s.%s at %p>",
PyString_AsString(mod),
name, op);
}
static PyObject *
class_str(PyClassObject *op)
{
PyObject *mod = PyDict_GetItemString(op->cl_dict, "__module__");
PyObject *name = op->cl_name;
PyObject *res;
int m, n;
if (name == NULL || !PyString_Check(name))
return class_repr(op);
if (mod == NULL || !PyString_Check(mod)) {
Py_INCREF(name);
return name;
}
m = PyString_Size(mod);
n = PyString_Size(name);
res = PyString_FromStringAndSize((char *)NULL, m+1+n);
if (res != NULL) {
char *s = PyString_AsString(res);
memcpy(s, PyString_AsString(mod), m);
s += m;
*s++ = '.';
memcpy(s, PyString_AsString(name), n);
}
return res;
}
static int
class_traverse(PyClassObject *o, visitproc visit, void *arg)
{
int err;
if (o->cl_bases) {
err = visit(o->cl_bases, arg);
if (err)
return err;
}
if (o->cl_dict) {
err = visit(o->cl_dict, arg);
if (err)
return err;
}
if (o->cl_name) {
err = visit(o->cl_name, arg);
if (err)
return err;
}
if (o->cl_getattr) {
err = visit(o->cl_getattr, arg);
if (err)
return err;
}
if (o->cl_setattr) {
err = visit(o->cl_setattr, arg);
if (err)
return err;
}
if (o->cl_delattr) {
err = visit(o->cl_delattr, arg);
if (err)
return err;
}
return 0;
}
#ifndef SYMBIAN
PyTypeObject PyClass_Type = {
PyObject_HEAD_INIT(&PyType_Type)
#else
const PyTypeObject c_PyClass_Type = {
PyObject_HEAD_INIT(NULL)
#endif
0,
"class",
sizeof(PyClassObject),
0,
(destructor)class_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)class_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
PyInstance_New, /* tp_call */
(reprfunc)class_str, /* tp_str */
(getattrofunc)class_getattr, /* tp_getattro */
(setattrofunc)class_setattr, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
0, /* tp_doc */
(traverseproc)class_traverse, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
class_new, /* tp_new */
};
DL_EXPORT(int)
PyClass_IsSubclass(PyObject *class, PyObject *base)
{
int i, n;
PyClassObject *cp;
if (class == base)
return 1;
if (class == NULL || !PyClass_Check(class))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -