You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
875 lines
20 KiB
875 lines
20 KiB
|
|
/* Function object implementation */ |
|
|
|
#include "Python.h" |
|
#include "compile.h" |
|
#include "eval.h" |
|
#include "structmember.h" |
|
|
|
PyObject * |
|
PyFunction_New(PyObject *code, PyObject *globals) |
|
{ |
|
PyFunctionObject *op = PyObject_GC_New(PyFunctionObject, |
|
&PyFunction_Type); |
|
if (op != NULL) { |
|
PyObject *doc; |
|
PyObject *consts; |
|
PyObject *module; |
|
op->func_weakreflist = NULL; |
|
Py_INCREF(code); |
|
op->func_code = code; |
|
Py_INCREF(globals); |
|
op->func_globals = globals; |
|
op->func_name = ((PyCodeObject *)code)->co_name; |
|
Py_INCREF(op->func_name); |
|
op->func_defaults = NULL; /* No default arguments */ |
|
op->func_closure = NULL; |
|
consts = ((PyCodeObject *)code)->co_consts; |
|
if (PyTuple_Size(consts) >= 1) { |
|
doc = PyTuple_GetItem(consts, 0); |
|
if (!PyString_Check(doc) && !PyUnicode_Check(doc)) |
|
doc = Py_None; |
|
} |
|
else |
|
doc = Py_None; |
|
Py_INCREF(doc); |
|
op->func_doc = doc; |
|
op->func_dict = NULL; |
|
op->func_module = NULL; |
|
|
|
/* __module__: If module name is in globals, use it. |
|
Otherwise, use None. |
|
*/ |
|
module = PyDict_GetItemString(globals, "__name__"); |
|
if (module) { |
|
Py_INCREF(module); |
|
op->func_module = module; |
|
} |
|
} |
|
else |
|
return NULL; |
|
_PyObject_GC_TRACK(op); |
|
return (PyObject *)op; |
|
} |
|
|
|
PyObject * |
|
PyFunction_GetCode(PyObject *op) |
|
{ |
|
if (!PyFunction_Check(op)) { |
|
PyErr_BadInternalCall(); |
|
return NULL; |
|
} |
|
return ((PyFunctionObject *) op) -> func_code; |
|
} |
|
|
|
PyObject * |
|
PyFunction_GetGlobals(PyObject *op) |
|
{ |
|
if (!PyFunction_Check(op)) { |
|
PyErr_BadInternalCall(); |
|
return NULL; |
|
} |
|
return ((PyFunctionObject *) op) -> func_globals; |
|
} |
|
|
|
PyObject * |
|
PyFunction_GetModule(PyObject *op) |
|
{ |
|
if (!PyFunction_Check(op)) { |
|
PyErr_BadInternalCall(); |
|
return NULL; |
|
} |
|
return ((PyFunctionObject *) op) -> func_module; |
|
} |
|
|
|
PyObject * |
|
PyFunction_GetDefaults(PyObject *op) |
|
{ |
|
if (!PyFunction_Check(op)) { |
|
PyErr_BadInternalCall(); |
|
return NULL; |
|
} |
|
return ((PyFunctionObject *) op) -> func_defaults; |
|
} |
|
|
|
int |
|
PyFunction_SetDefaults(PyObject *op, PyObject *defaults) |
|
{ |
|
if (!PyFunction_Check(op)) { |
|
PyErr_BadInternalCall(); |
|
return -1; |
|
} |
|
if (defaults == Py_None) |
|
defaults = NULL; |
|
else if (PyTuple_Check(defaults)) { |
|
Py_XINCREF(defaults); |
|
} |
|
else { |
|
PyErr_SetString(PyExc_SystemError, "non-tuple default args"); |
|
return -1; |
|
} |
|
Py_XDECREF(((PyFunctionObject *) op) -> func_defaults); |
|
((PyFunctionObject *) op) -> func_defaults = defaults; |
|
return 0; |
|
} |
|
|
|
PyObject * |
|
PyFunction_GetClosure(PyObject *op) |
|
{ |
|
if (!PyFunction_Check(op)) { |
|
PyErr_BadInternalCall(); |
|
return NULL; |
|
} |
|
return ((PyFunctionObject *) op) -> func_closure; |
|
} |
|
|
|
int |
|
PyFunction_SetClosure(PyObject *op, PyObject *closure) |
|
{ |
|
if (!PyFunction_Check(op)) { |
|
PyErr_BadInternalCall(); |
|
return -1; |
|
} |
|
if (closure == Py_None) |
|
closure = NULL; |
|
else if (PyTuple_Check(closure)) { |
|
Py_XINCREF(closure); |
|
} |
|
else { |
|
PyErr_SetString(PyExc_SystemError, "non-tuple closure"); |
|
return -1; |
|
} |
|
Py_XDECREF(((PyFunctionObject *) op) -> func_closure); |
|
((PyFunctionObject *) op) -> func_closure = closure; |
|
return 0; |
|
} |
|
|
|
/* Methods */ |
|
|
|
#define OFF(x) offsetof(PyFunctionObject, x) |
|
|
|
#define RR () |
|
|
|
static PyMemberDef func_memberlist[] = { |
|
{"func_closure", T_OBJECT, OFF(func_closure), |
|
RESTRICTED|READONLY}, |
|
{"func_doc", T_OBJECT, OFF(func_doc), PY_WRITE_RESTRICTED}, |
|
{"__doc__", T_OBJECT, OFF(func_doc), PY_WRITE_RESTRICTED}, |
|
{"func_globals", T_OBJECT, OFF(func_globals), |
|
RESTRICTED|READONLY}, |
|
{"func_name", T_OBJECT, OFF(func_name), READONLY}, |
|
{"__name__", T_OBJECT, OFF(func_name), READONLY}, |
|
{"__module__", T_OBJECT, OFF(func_module), PY_WRITE_RESTRICTED}, |
|
{NULL} /* Sentinel */ |
|
}; |
|
|
|
static int |
|
restricted(void) |
|
{ |
|
if (!PyEval_GetRestricted()) |
|
return 0; |
|
PyErr_SetString(PyExc_RuntimeError, |
|
"function attributes not accessible in restricted mode"); |
|
return 1; |
|
} |
|
|
|
static PyObject * |
|
func_get_dict(PyFunctionObject *op) |
|
{ |
|
if (restricted()) |
|
return NULL; |
|
if (op->func_dict == NULL) { |
|
op->func_dict = PyDict_New(); |
|
if (op->func_dict == NULL) |
|
return NULL; |
|
} |
|
Py_INCREF(op->func_dict); |
|
return op->func_dict; |
|
} |
|
|
|
static int |
|
func_set_dict(PyFunctionObject *op, PyObject *value) |
|
{ |
|
PyObject *tmp; |
|
|
|
if (restricted()) |
|
return -1; |
|
/* It is illegal to del f.func_dict */ |
|
if (value == NULL) { |
|
PyErr_SetString(PyExc_TypeError, |
|
"function's dictionary may not be deleted"); |
|
return -1; |
|
} |
|
/* Can only set func_dict to a dictionary */ |
|
if (!PyDict_Check(value)) { |
|
PyErr_SetString(PyExc_TypeError, |
|
"setting function's dictionary to a non-dict"); |
|
return -1; |
|
} |
|
tmp = op->func_dict; |
|
Py_INCREF(value); |
|
op->func_dict = value; |
|
Py_XDECREF(tmp); |
|
return 0; |
|
} |
|
|
|
static PyObject * |
|
func_get_code(PyFunctionObject *op) |
|
{ |
|
if (restricted()) |
|
return NULL; |
|
Py_INCREF(op->func_code); |
|
return op->func_code; |
|
} |
|
|
|
static int |
|
func_set_code(PyFunctionObject *op, PyObject *value) |
|
{ |
|
PyObject *tmp; |
|
|
|
if (restricted()) |
|
return -1; |
|
/* Not legal to del f.func_code or to set it to anything |
|
* other than a code object. */ |
|
if (value == NULL || !PyCode_Check(value)) { |
|
PyErr_SetString(PyExc_TypeError, |
|
"func_code must be set to a code object"); |
|
return -1; |
|
} |
|
tmp = op->func_code; |
|
Py_INCREF(value); |
|
op->func_code = value; |
|
Py_DECREF(tmp); |
|
return 0; |
|
} |
|
|
|
static PyObject * |
|
func_get_defaults(PyFunctionObject *op) |
|
{ |
|
if (restricted()) |
|
return NULL; |
|
if (op->func_defaults == NULL) { |
|
Py_INCREF(Py_None); |
|
return Py_None; |
|
} |
|
Py_INCREF(op->func_defaults); |
|
return op->func_defaults; |
|
} |
|
|
|
static int |
|
func_set_defaults(PyFunctionObject *op, PyObject *value) |
|
{ |
|
PyObject *tmp; |
|
|
|
if (restricted()) |
|
return -1; |
|
/* Legal to del f.func_defaults. |
|
* Can only set func_defaults to NULL or a tuple. */ |
|
if (value == Py_None) |
|
value = NULL; |
|
if (value != NULL && !PyTuple_Check(value)) { |
|
PyErr_SetString(PyExc_TypeError, |
|
"func_defaults must be set to a tuple object"); |
|
return -1; |
|
} |
|
tmp = op->func_defaults; |
|
Py_XINCREF(value); |
|
op->func_defaults = value; |
|
Py_XDECREF(tmp); |
|
return 0; |
|
} |
|
|
|
static PyGetSetDef func_getsetlist[] = { |
|
{"func_code", (getter)func_get_code, (setter)func_set_code}, |
|
{"func_defaults", (getter)func_get_defaults, |
|
(setter)func_set_defaults}, |
|
{"func_dict", (getter)func_get_dict, (setter)func_set_dict}, |
|
{"__dict__", (getter)func_get_dict, (setter)func_set_dict}, |
|
{NULL} /* Sentinel */ |
|
}; |
|
|
|
PyDoc_STRVAR(func_doc, |
|
"function(code, globals[, name[, argdefs[, closure]]])\n\ |
|
\n\ |
|
Create a function object from a code object and a dictionary.\n\ |
|
The optional name string overrides the name from the code object.\n\ |
|
The optional argdefs tuple specifies the default argument values.\n\ |
|
The optional closure tuple supplies the bindings for free variables."); |
|
|
|
/* func_new() maintains the following invariants for closures. The |
|
closure must correspond to the free variables of the code object. |
|
|
|
if len(code.co_freevars) == 0: |
|
closure = NULL |
|
else: |
|
len(closure) == len(code.co_freevars) |
|
for every elt in closure, type(elt) == cell |
|
*/ |
|
|
|
static PyObject * |
|
func_new(PyTypeObject* type, PyObject* args, PyObject* kw) |
|
{ |
|
PyCodeObject *code; |
|
PyObject *globals; |
|
PyObject *name = Py_None; |
|
PyObject *defaults = Py_None; |
|
PyObject *closure = Py_None; |
|
PyFunctionObject *newfunc; |
|
int nfree, nclosure; |
|
static char *kwlist[] = {"code", "globals", "name", |
|
"argdefs", "closure", 0}; |
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kw, "O!O!|OOO:function", |
|
kwlist, |
|
&PyCode_Type, &code, |
|
&PyDict_Type, &globals, |
|
&name, &defaults, &closure)) |
|
return NULL; |
|
if (name != Py_None && !PyString_Check(name)) { |
|
PyErr_SetString(PyExc_TypeError, |
|
"arg 3 (name) must be None or string"); |
|
return NULL; |
|
} |
|
if (defaults != Py_None && !PyTuple_Check(defaults)) { |
|
PyErr_SetString(PyExc_TypeError, |
|
"arg 4 (defaults) must be None or tuple"); |
|
return NULL; |
|
} |
|
nfree = PyTuple_GET_SIZE(code->co_freevars); |
|
if (!PyTuple_Check(closure)) { |
|
if (nfree && closure == Py_None) { |
|
PyErr_SetString(PyExc_TypeError, |
|
"arg 5 (closure) must be tuple"); |
|
return NULL; |
|
} |
|
else if (closure != Py_None) { |
|
PyErr_SetString(PyExc_TypeError, |
|
"arg 5 (closure) must be None or tuple"); |
|
return NULL; |
|
} |
|
} |
|
|
|
/* check that the closure is well-formed */ |
|
nclosure = closure == Py_None ? 0 : PyTuple_GET_SIZE(closure); |
|
if (nfree != nclosure) |
|
return PyErr_Format(PyExc_ValueError, |
|
"%s requires closure of length %d, not %d", |
|
PyString_AS_STRING(code->co_name), |
|
nfree, nclosure); |
|
if (nclosure) { |
|
int i; |
|
for (i = 0; i < nclosure; i++) { |
|
PyObject *o = PyTuple_GET_ITEM(closure, i); |
|
if (!PyCell_Check(o)) { |
|
return PyErr_Format(PyExc_TypeError, |
|
"arg 5 (closure) expected cell, found %s", |
|
o->ob_type->tp_name); |
|
} |
|
} |
|
} |
|
|
|
newfunc = (PyFunctionObject *)PyFunction_New((PyObject *)code, |
|
globals); |
|
if (newfunc == NULL) |
|
return NULL; |
|
|
|
if (name != Py_None) { |
|
Py_INCREF(name); |
|
Py_DECREF(newfunc->func_name); |
|
newfunc->func_name = name; |
|
} |
|
if (defaults != Py_None) { |
|
Py_INCREF(defaults); |
|
newfunc->func_defaults = defaults; |
|
} |
|
if (closure != Py_None) { |
|
Py_INCREF(closure); |
|
newfunc->func_closure = closure; |
|
} |
|
|
|
return (PyObject *)newfunc; |
|
} |
|
|
|
static void |
|
func_dealloc(PyFunctionObject *op) |
|
{ |
|
_PyObject_GC_UNTRACK(op); |
|
if (op->func_weakreflist != NULL) |
|
PyObject_ClearWeakRefs((PyObject *) op); |
|
Py_DECREF(op->func_code); |
|
Py_DECREF(op->func_globals); |
|
Py_XDECREF(op->func_module); |
|
Py_DECREF(op->func_name); |
|
Py_XDECREF(op->func_defaults); |
|
Py_XDECREF(op->func_doc); |
|
Py_XDECREF(op->func_dict); |
|
Py_XDECREF(op->func_closure); |
|
PyObject_GC_Del(op); |
|
} |
|
|
|
static PyObject* |
|
func_repr(PyFunctionObject *op) |
|
{ |
|
if (op->func_name == Py_None) |
|
return PyString_FromFormat("<anonymous function at %p>", op); |
|
return PyString_FromFormat("<function %s at %p>", |
|
PyString_AsString(op->func_name), |
|
op); |
|
} |
|
|
|
static int |
|
func_traverse(PyFunctionObject *f, visitproc visit, void *arg) |
|
{ |
|
int err; |
|
if (f->func_code) { |
|
err = visit(f->func_code, arg); |
|
if (err) |
|
return err; |
|
} |
|
if (f->func_globals) { |
|
err = visit(f->func_globals, arg); |
|
if (err) |
|
return err; |
|
} |
|
if (f->func_module) { |
|
err = visit(f->func_module, arg); |
|
if (err) |
|
return err; |
|
} |
|
if (f->func_defaults) { |
|
err = visit(f->func_defaults, arg); |
|
if (err) |
|
return err; |
|
} |
|
if (f->func_doc) { |
|
err = visit(f->func_doc, arg); |
|
if (err) |
|
return err; |
|
} |
|
if (f->func_name) { |
|
err = visit(f->func_name, arg); |
|
if (err) |
|
return err; |
|
} |
|
if (f->func_dict) { |
|
err = visit(f->func_dict, arg); |
|
if (err) |
|
return err; |
|
} |
|
if (f->func_closure) { |
|
err = visit(f->func_closure, arg); |
|
if (err) |
|
return err; |
|
} |
|
return 0; |
|
} |
|
|
|
static PyObject * |
|
function_call(PyObject *func, PyObject *arg, PyObject *kw) |
|
{ |
|
PyObject *result; |
|
PyObject *argdefs; |
|
PyObject **d, **k; |
|
int nk, nd; |
|
|
|
argdefs = PyFunction_GET_DEFAULTS(func); |
|
if (argdefs != NULL && PyTuple_Check(argdefs)) { |
|
d = &PyTuple_GET_ITEM((PyTupleObject *)argdefs, 0); |
|
nd = PyTuple_Size(argdefs); |
|
} |
|
else { |
|
d = NULL; |
|
nd = 0; |
|
} |
|
|
|
if (kw != NULL && PyDict_Check(kw)) { |
|
int pos, i; |
|
nk = PyDict_Size(kw); |
|
k = PyMem_NEW(PyObject *, 2*nk); |
|
if (k == NULL) { |
|
PyErr_NoMemory(); |
|
return NULL; |
|
} |
|
pos = i = 0; |
|
while (PyDict_Next(kw, &pos, &k[i], &k[i+1])) |
|
i += 2; |
|
nk = i/2; |
|
/* XXX This is broken if the caller deletes dict items! */ |
|
} |
|
else { |
|
k = NULL; |
|
nk = 0; |
|
} |
|
|
|
result = PyEval_EvalCodeEx( |
|
(PyCodeObject *)PyFunction_GET_CODE(func), |
|
PyFunction_GET_GLOBALS(func), (PyObject *)NULL, |
|
&PyTuple_GET_ITEM(arg, 0), PyTuple_Size(arg), |
|
k, nk, d, nd, |
|
PyFunction_GET_CLOSURE(func)); |
|
|
|
if (k != NULL) |
|
PyMem_DEL(k); |
|
|
|
return result; |
|
} |
|
|
|
/* Bind a function to an object */ |
|
static PyObject * |
|
func_descr_get(PyObject *func, PyObject *obj, PyObject *type) |
|
{ |
|
if (obj == Py_None) |
|
obj = NULL; |
|
return PyMethod_New(func, obj, type); |
|
} |
|
|
|
PyTypeObject PyFunction_Type = { |
|
PyObject_HEAD_INIT(&PyType_Type) |
|
0, |
|
"function", |
|
sizeof(PyFunctionObject), |
|
0, |
|
(destructor)func_dealloc, /* tp_dealloc */ |
|
0, /* tp_print */ |
|
0, /* tp_getattr */ |
|
0, /* tp_setattr */ |
|
0, /* tp_compare */ |
|
(reprfunc)func_repr, /* tp_repr */ |
|
0, /* tp_as_number */ |
|
0, /* tp_as_sequence */ |
|
0, /* tp_as_mapping */ |
|
0, /* tp_hash */ |
|
function_call, /* tp_call */ |
|
0, /* tp_str */ |
|
PyObject_GenericGetAttr, /* tp_getattro */ |
|
PyObject_GenericSetAttr, /* tp_setattro */ |
|
0, /* tp_as_buffer */ |
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ |
|
func_doc, /* tp_doc */ |
|
(traverseproc)func_traverse, /* tp_traverse */ |
|
0, /* tp_clear */ |
|
0, /* tp_richcompare */ |
|
offsetof(PyFunctionObject, func_weakreflist), /* tp_weaklistoffset */ |
|
0, /* tp_iter */ |
|
0, /* tp_iternext */ |
|
0, /* tp_methods */ |
|
func_memberlist, /* tp_members */ |
|
func_getsetlist, /* tp_getset */ |
|
0, /* tp_base */ |
|
0, /* tp_dict */ |
|
func_descr_get, /* tp_descr_get */ |
|
0, /* tp_descr_set */ |
|
offsetof(PyFunctionObject, func_dict), /* tp_dictoffset */ |
|
0, /* tp_init */ |
|
0, /* tp_alloc */ |
|
func_new, /* tp_new */ |
|
}; |
|
|
|
|
|
/* Class method object */ |
|
|
|
/* A class method receives the class as implicit first argument, |
|
just like an instance method receives the instance. |
|
To declare a class method, use this idiom: |
|
|
|
class C: |
|
def f(cls, arg1, arg2, ...): ... |
|
f = classmethod(f) |
|
|
|
It can be called either on the class (e.g. C.f()) or on an instance |
|
(e.g. C().f()); the instance is ignored except for its class. |
|
If a class method is called for a derived class, the derived class |
|
object is passed as the implied first argument. |
|
|
|
Class methods are different than C++ or Java static methods. |
|
If you want those, see static methods below. |
|
*/ |
|
|
|
typedef struct { |
|
PyObject_HEAD |
|
PyObject *cm_callable; |
|
} classmethod; |
|
|
|
static void |
|
cm_dealloc(classmethod *cm) |
|
{ |
|
_PyObject_GC_UNTRACK((PyObject *)cm); |
|
Py_XDECREF(cm->cm_callable); |
|
cm->ob_type->tp_free((PyObject *)cm); |
|
} |
|
|
|
static int |
|
cm_traverse(classmethod *cm, visitproc visit, void *arg) |
|
{ |
|
if (!cm->cm_callable) |
|
return 0; |
|
return visit(cm->cm_callable, arg); |
|
} |
|
|
|
static int |
|
cm_clear(classmethod *cm) |
|
{ |
|
Py_XDECREF(cm->cm_callable); |
|
cm->cm_callable = NULL; |
|
|
|
return 0; |
|
} |
|
|
|
|
|
static PyObject * |
|
cm_descr_get(PyObject *self, PyObject *obj, PyObject *type) |
|
{ |
|
classmethod *cm = (classmethod *)self; |
|
|
|
if (cm->cm_callable == NULL) { |
|
PyErr_SetString(PyExc_RuntimeError, |
|
"uninitialized classmethod object"); |
|
return NULL; |
|
} |
|
if (type == NULL) |
|
type = (PyObject *)(obj->ob_type); |
|
return PyMethod_New(cm->cm_callable, |
|
type, (PyObject *)(type->ob_type)); |
|
} |
|
|
|
static int |
|
cm_init(PyObject *self, PyObject *args, PyObject *kwds) |
|
{ |
|
classmethod *cm = (classmethod *)self; |
|
PyObject *callable; |
|
|
|
if (!PyArg_UnpackTuple(args, "classmethod", 1, 1, &callable)) |
|
return -1; |
|
if (!PyCallable_Check(callable)) { |
|
PyErr_Format(PyExc_TypeError, "'%s' object is not callable", |
|
callable->ob_type->tp_name); |
|
return -1; |
|
} |
|
|
|
Py_INCREF(callable); |
|
cm->cm_callable = callable; |
|
return 0; |
|
} |
|
|
|
PyDoc_STRVAR(classmethod_doc, |
|
"classmethod(function) -> method\n\ |
|
\n\ |
|
Convert a function to be a class method.\n\ |
|
\n\ |
|
A class method receives the class as implicit first argument,\n\ |
|
just like an instance method receives the instance.\n\ |
|
To declare a class method, use this idiom:\n\ |
|
\n\ |
|
class C:\n\ |
|
def f(cls, arg1, arg2, ...): ...\n\ |
|
f = classmethod(f)\n\ |
|
\n\ |
|
It can be called either on the class (e.g. C.f()) or on an instance\n\ |
|
(e.g. C().f()). The instance is ignored except for its class.\n\ |
|
If a class method is called for a derived class, the derived class\n\ |
|
object is passed as the implied first argument.\n\ |
|
\n\ |
|
Class methods are different than C++ or Java static methods.\n\ |
|
If you want those, see the staticmethod builtin."); |
|
|
|
PyTypeObject PyClassMethod_Type = { |
|
PyObject_HEAD_INIT(&PyType_Type) |
|
0, |
|
"classmethod", |
|
sizeof(classmethod), |
|
0, |
|
(destructor)cm_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 */ |
|
PyObject_GenericGetAttr, /* tp_getattro */ |
|
0, /* tp_setattro */ |
|
0, /* tp_as_buffer */ |
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, |
|
classmethod_doc, /* tp_doc */ |
|
(traverseproc)cm_traverse, /* tp_traverse */ |
|
(inquiry)cm_clear, /* 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 */ |
|
cm_descr_get, /* tp_descr_get */ |
|
0, /* tp_descr_set */ |
|
0, /* tp_dictoffset */ |
|
cm_init, /* tp_init */ |
|
PyType_GenericAlloc, /* tp_alloc */ |
|
PyType_GenericNew, /* tp_new */ |
|
PyObject_GC_Del, /* tp_free */ |
|
}; |
|
|
|
PyObject * |
|
PyClassMethod_New(PyObject *callable) |
|
{ |
|
classmethod *cm = (classmethod *) |
|
PyType_GenericAlloc(&PyClassMethod_Type, 0); |
|
if (cm != NULL) { |
|
Py_INCREF(callable); |
|
cm->cm_callable = callable; |
|
} |
|
return (PyObject *)cm; |
|
} |
|
|
|
|
|
/* Static method object */ |
|
|
|
/* A static method does not receive an implicit first argument. |
|
To declare a static method, use this idiom: |
|
|
|
class C: |
|
def f(arg1, arg2, ...): ... |
|
f = staticmethod(f) |
|
|
|
It can be called either on the class (e.g. C.f()) or on an instance |
|
(e.g. C().f()); the instance is ignored except for its class. |
|
|
|
Static methods in Python are similar to those found in Java or C++. |
|
For a more advanced concept, see class methods above. |
|
*/ |
|
|
|
typedef struct { |
|
PyObject_HEAD |
|
PyObject *sm_callable; |
|
} staticmethod; |
|
|
|
static void |
|
sm_dealloc(staticmethod *sm) |
|
{ |
|
_PyObject_GC_UNTRACK((PyObject *)sm); |
|
Py_XDECREF(sm->sm_callable); |
|
sm->ob_type->tp_free((PyObject *)sm); |
|
} |
|
|
|
static int |
|
sm_traverse(staticmethod *sm, visitproc visit, void *arg) |
|
{ |
|
if (!sm->sm_callable) |
|
return 0; |
|
return visit(sm->sm_callable, arg); |
|
} |
|
|
|
static int |
|
sm_clear(staticmethod *sm) |
|
{ |
|
Py_XDECREF(sm->sm_callable); |
|
sm->sm_callable = NULL; |
|
|
|
return 0; |
|
} |
|
|
|
static PyObject * |
|
sm_descr_get(PyObject *self, PyObject *obj, PyObject *type) |
|
{ |
|
staticmethod *sm = (staticmethod *)self; |
|
|
|
if (sm->sm_callable == NULL) { |
|
PyErr_SetString(PyExc_RuntimeError, |
|
"uninitialized staticmethod object"); |
|
return NULL; |
|
} |
|
Py_INCREF(sm->sm_callable); |
|
return sm->sm_callable; |
|
} |
|
|
|
static int |
|
sm_init(PyObject *self, PyObject *args, PyObject *kwds) |
|
{ |
|
staticmethod *sm = (staticmethod *)self; |
|
PyObject *callable; |
|
|
|
if (!PyArg_UnpackTuple(args, "staticmethod", 1, 1, &callable)) |
|
return -1; |
|
Py_INCREF(callable); |
|
sm->sm_callable = callable; |
|
return 0; |
|
} |
|
|
|
PyDoc_STRVAR(staticmethod_doc, |
|
"staticmethod(function) -> method\n\ |
|
\n\ |
|
Convert a function to be a static method.\n\ |
|
\n\ |
|
A static method does not receive an implicit first argument.\n\ |
|
To declare a static method, use this idiom:\n\ |
|
\n\ |
|
class C:\n\ |
|
def f(arg1, arg2, ...): ...\n\ |
|
f = staticmethod(f)\n\ |
|
\n\ |
|
It can be called either on the class (e.g. C.f()) or on an instance\n\ |
|
(e.g. C().f()). The instance is ignored except for its class.\n\ |
|
\n\ |
|
Static methods in Python are similar to those found in Java or C++.\n\ |
|
For a more advanced concept, see the classmethod builtin."); |
|
|
|
PyTypeObject PyStaticMethod_Type = { |
|
PyObject_HEAD_INIT(&PyType_Type) |
|
0, |
|
"staticmethod", |
|
sizeof(staticmethod), |
|
0, |
|
(destructor)sm_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 */ |
|
PyObject_GenericGetAttr, /* tp_getattro */ |
|
0, /* tp_setattro */ |
|
0, /* tp_as_buffer */ |
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, |
|
staticmethod_doc, /* tp_doc */ |
|
(traverseproc)sm_traverse, /* tp_traverse */ |
|
(inquiry)sm_clear, /* 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 */ |
|
sm_descr_get, /* tp_descr_get */ |
|
0, /* tp_descr_set */ |
|
0, /* tp_dictoffset */ |
|
sm_init, /* tp_init */ |
|
PyType_GenericAlloc, /* tp_alloc */ |
|
PyType_GenericNew, /* tp_new */ |
|
PyObject_GC_Del, /* tp_free */ |
|
}; |
|
|
|
PyObject * |
|
PyStaticMethod_New(PyObject *callable) |
|
{ |
|
staticmethod *sm = (staticmethod *) |
|
PyType_GenericAlloc(&PyStaticMethod_Type, 0); |
|
if (sm != NULL) { |
|
Py_INCREF(callable); |
|
sm->sm_callable = callable; |
|
} |
|
return (PyObject *)sm; |
|
}
|
|
|