Skip to content

Commit 4e38a9e

Browse files
author
fdrake
committed
Introduce two new flag bits that can be set in a PyMethodDef method
descriptor, as used for the tp_methods slot of a type. These new flag bits are both optional, and mutually exclusive. Most methods will not use either. These flags are used to create special method types which exist in the same namespace as normal methods without having to use tedious construction code to insert the new special method objects in the type's tp_dict after PyType_Ready() has been called. If METH_CLASS is specified, the method will represent a class method like that returned by the classmethod() built-in. If METH_STATIC is specified, the method will represent a static method like that returned by the staticmethod() built-in. These flags may not be used in the PyMethodDef table for modules since these special method types are not meaningful in that case; a ValueError will be raised if these flags are found in that context. git-svn-id: http://svn.python.org/projects/python/trunk@25975 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent 1b34993 commit 4e38a9e

5 files changed

Lines changed: 74 additions & 6 deletions

File tree

Doc/api/newtypes.tex

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,12 @@ \section{Common Object Structures \label{common-structs}}
152152
the first parameter as \ctype{PyObject*}, it is common that the method
153153
implementation uses a the specific C type of the \var{self} object.
154154

155-
The flags can have the following values. Only \constant{METH_VARARGS}
156-
and \constant{METH_KEYWORDS} can be combined; the others can't.
155+
The \member{ml_flags} field is a bitfield which can include the
156+
following flags. The individual flags indicate either a calling
157+
convention or a binding convention. Of the calling convention flags,
158+
only \constant{METH_VARARGS} and \constant{METH_KEYWORDS} can be
159+
combined. Any of the calling convention flags can be combined with a
160+
binding flag.
157161

158162
\begin{datadesc}{METH_VARARGS}
159163
This is the typical calling convention, where the methods have the
@@ -203,6 +207,30 @@ \section{Common Object Structures \label{common-structs}}
203207
argument.
204208
\end{datadesc}
205209

210+
These two constants are not used to indicate the calling convention
211+
but the binding when use with methods of classes. These may not be
212+
used for functions defined for modules. At most one of these flags
213+
may be set for any given method.
214+
215+
\begin{datadesc}{METH_CLASS}
216+
The method will be passed the type object as the first parameter
217+
rather than an instance of the type. This is used to create
218+
\emph{class methods}, similar to what is created when using the
219+
\function{classmethod()}\bifuncindex{classmethod} built-in
220+
function.
221+
\versionadded{2.3}
222+
\end{datadesc}
223+
224+
\begin{datadesc}{METH_STATIC}
225+
The method will be passed \NULL{} as the first parameter rather than
226+
an instance of the type. This is used to create \emph{static
227+
methods}, similar to what is created when using the
228+
\function{staticmethod()}\bifuncindex{staticmethod} built-in
229+
function.
230+
\versionadded{2.3}
231+
\end{datadesc}
232+
233+
206234
\begin{cfuncdesc}{PyObject*}{Py_FindMethod}{PyMethodDef table[],
207235
PyObject *ob, char *name}
208236
Return a bound method object for an extension type implemented in

Include/methodobject.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,16 @@ extern DL_IMPORT(PyObject *) PyCFunction_New(PyMethodDef *, PyObject *);
4646
#define METH_OLDARGS 0x0000
4747
#define METH_VARARGS 0x0001
4848
#define METH_KEYWORDS 0x0002
49-
/* METH_NOARGS and METH_O must not be combined with any other flag. */
49+
/* METH_NOARGS and METH_O must not be combined with the flags above. */
5050
#define METH_NOARGS 0x0004
5151
#define METH_O 0x0008
5252

53+
/* METH_CLASS and METH_STATIC are a little different; these control
54+
the construction of methods for a class. These cannot be used for
55+
functions in modules. */
56+
#define METH_CLASS 0x0010
57+
#define METH_STATIC 0x0020
58+
5359
typedef struct PyMethodChain {
5460
PyMethodDef *methods; /* Methods of this type */
5561
struct PyMethodChain *link; /* NULL or base type */

Objects/methodobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ PyCFunction_Call(PyObject *func, PyObject *arg, PyObject *kw)
6262
PyCFunctionObject* f = (PyCFunctionObject*)func;
6363
PyCFunction meth = PyCFunction_GET_FUNCTION(func);
6464
PyObject *self = PyCFunction_GET_SELF(func);
65-
int flags = PyCFunction_GET_FLAGS(func);
65+
int flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC);
6666
int size = PyTuple_GET_SIZE(arg);
6767

6868
if (flags & METH_KEYWORDS) {

Objects/typeobject.c

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1694,6 +1694,20 @@ PyTypeObject PyBaseObject_Type = {
16941694

16951695
/* Initialize the __dict__ in a type object */
16961696

1697+
static PyObject *
1698+
create_specialmethod(PyMethodDef *meth, PyObject *(*func)(PyObject *))
1699+
{
1700+
PyObject *cfunc;
1701+
PyObject *result;
1702+
1703+
cfunc = PyCFunction_New(meth, NULL);
1704+
if (cfunc == NULL)
1705+
return NULL;
1706+
result = func(cfunc);
1707+
Py_DECREF(cfunc);
1708+
return result;
1709+
}
1710+
16971711
static int
16981712
add_methods(PyTypeObject *type, PyMethodDef *meth)
16991713
{
@@ -1703,10 +1717,23 @@ add_methods(PyTypeObject *type, PyMethodDef *meth)
17031717
PyObject *descr;
17041718
if (PyDict_GetItemString(dict, meth->ml_name))
17051719
continue;
1706-
descr = PyDescr_NewMethod(type, meth);
1720+
if (meth->ml_flags & METH_CLASS) {
1721+
if (meth->ml_flags & METH_STATIC) {
1722+
PyErr_SetString(PyExc_ValueError,
1723+
"method cannot be both class and static");
1724+
return -1;
1725+
}
1726+
descr = create_specialmethod(meth, PyClassMethod_New);
1727+
}
1728+
else if (meth->ml_flags & METH_STATIC) {
1729+
descr = create_specialmethod(meth, PyStaticMethod_New);
1730+
}
1731+
else {
1732+
descr = PyDescr_NewMethod(type, meth);
1733+
}
17071734
if (descr == NULL)
17081735
return -1;
1709-
if (PyDict_SetItemString(dict,meth->ml_name, descr) < 0)
1736+
if (PyDict_SetItemString(dict, meth->ml_name, descr) < 0)
17101737
return -1;
17111738
Py_DECREF(descr);
17121739
}

Python/modsupport.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ Py_InitModule4(char *name, PyMethodDef *methods, char *doc,
5757
return NULL;
5858
d = PyModule_GetDict(m);
5959
for (ml = methods; ml->ml_name != NULL; ml++) {
60+
if ((ml->ml_flags & METH_CLASS) ||
61+
(ml->ml_flags & METH_STATIC)) {
62+
PyErr_SetString(PyExc_ValueError,
63+
"module functions cannot set"
64+
" METH_CLASS or METH_STATIC");
65+
return NULL;
66+
}
6067
v = PyCFunction_New(ml, passthrough);
6168
if (v == NULL)
6269
return NULL;

0 commit comments

Comments
 (0)