Skip to content

Commit 553ee27

Browse files
authored
bpo-43682: Make staticmethod objects callable (GH-25117)
Static methods (@staticmethod) are now callable as regular functions.
1 parent 53114ff commit 553ee27

File tree

7 files changed

+32
-14
lines changed

7 files changed

+32
-14
lines changed

Doc/library/functions.rst

+10-5
Original file line numberDiff line numberDiff line change
@@ -1619,8 +1619,9 @@ are always available. They are listed here in alphabetical order.
16191619
The ``@staticmethod`` form is a function :term:`decorator` -- see
16201620
:ref:`function` for details.
16211621

1622-
A static method can be called either on the class (such as ``C.f()``) or on an instance (such
1623-
as ``C().f()``).
1622+
A static method can be called either on the class (such as ``C.f()``) or on
1623+
an instance (such as ``C().f()``). Moreover, they can be called as regular
1624+
functions (such as ``f()``).
16241625

16251626
Static methods in Python are similar to those found in Java or C++. Also see
16261627
:func:`classmethod` for a variant that is useful for creating alternate class
@@ -1632,15 +1633,19 @@ are always available. They are listed here in alphabetical order.
16321633
body and you want to avoid the automatic transformation to instance
16331634
method. For these cases, use this idiom::
16341635

1636+
def regular_function():
1637+
...
1638+
16351639
class C:
1636-
builtin_open = staticmethod(open)
1640+
method = staticmethod(regular_function)
16371641

16381642
For more information on static methods, see :ref:`types`.
16391643

16401644
.. versionchanged:: 3.10
16411645
Static methods now inherit the method attributes (``__module__``,
1642-
``__name__``, ``__qualname__``, ``__doc__`` and ``__annotations__``) and
1643-
have a new ``__wrapped__`` attribute.
1646+
``__name__``, ``__qualname__``, ``__doc__`` and ``__annotations__``),
1647+
have a new ``__wrapped__`` attribute, and are now callable as regular
1648+
functions.
16441649

16451650

16461651
.. index::

Doc/reference/datamodel.rst

+2-3
Original file line numberDiff line numberDiff line change
@@ -1132,9 +1132,8 @@ Internal types
11321132
around any other object, usually a user-defined method object. When a static
11331133
method object is retrieved from a class or a class instance, the object actually
11341134
returned is the wrapped object, which is not subject to any further
1135-
transformation. Static method objects are not themselves callable, although the
1136-
objects they wrap usually are. Static method objects are created by the built-in
1137-
:func:`staticmethod` constructor.
1135+
transformation. Static method objects are also callable. Static method
1136+
objects are created by the built-in :func:`staticmethod` constructor.
11381137

11391138
Class method objects
11401139
A class method object, like a static method object, is a wrapper around another

Doc/whatsnew/3.10.rst

+1
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,7 @@ Other Language Changes
623623
(:func:`@classmethod <classmethod>`) now inherit the method attributes
624624
(``__module__``, ``__name__``, ``__qualname__``, ``__doc__``,
625625
``__annotations__``) and have a new ``__wrapped__`` attribute.
626+
Moreover, static methods are now callable as regular functions.
626627
(Contributed by Victor Stinner in :issue:`43682`.)
627628
628629

Lib/test/test_decorators.py

+8-4
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,18 @@ def func(x):
9191
getattr(func, attr))
9292

9393
self.assertEqual(repr(wrapper), format_str.format(func))
94-
95-
self.assertRaises(TypeError, wrapper, 1)
94+
return wrapper
9695

9796
def test_staticmethod(self):
98-
self.check_wrapper_attrs(staticmethod, '<staticmethod({!r})>')
97+
wrapper = self.check_wrapper_attrs(staticmethod, '<staticmethod({!r})>')
98+
99+
# bpo-43682: Static methods are callable since Python 3.10
100+
self.assertEqual(wrapper(1), 1)
99101

100102
def test_classmethod(self):
101-
self.check_wrapper_attrs(classmethod, '<classmethod({!r})>')
103+
wrapper = self.check_wrapper_attrs(classmethod, '<classmethod({!r})>')
104+
105+
self.assertRaises(TypeError, wrapper, 1)
102106

103107
def test_dotted(self):
104108
decorators = MiscDecorators()

Lib/test/test_pydoc.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1142,7 +1142,7 @@ def sm(x, y):
11421142
'''A static method'''
11431143
...
11441144
self.assertEqual(self._get_summary_lines(X.__dict__['sm']),
1145-
'sm(...)\n'
1145+
'sm(x, y)\n'
11461146
' A static method\n')
11471147
self.assertEqual(self._get_summary_lines(X.sm), """\
11481148
sm(x, y)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Static methods (:func:`@staticmethod <staticmethod>`) are now callable as
2+
regular functions. Patch by Victor Stinner.

Objects/funcobject.c

+8-1
Original file line numberDiff line numberDiff line change
@@ -1040,6 +1040,13 @@ sm_init(PyObject *self, PyObject *args, PyObject *kwds)
10401040
return 0;
10411041
}
10421042

1043+
static PyObject*
1044+
sm_call(PyObject *callable, PyObject *args, PyObject *kwargs)
1045+
{
1046+
staticmethod *sm = (staticmethod *)callable;
1047+
return PyObject_Call(sm->sm_callable, args, kwargs);
1048+
}
1049+
10431050
static PyMemberDef sm_memberlist[] = {
10441051
{"__func__", T_OBJECT, offsetof(staticmethod, sm_callable), READONLY},
10451052
{"__wrapped__", T_OBJECT, offsetof(staticmethod, sm_callable), READONLY},
@@ -1107,7 +1114,7 @@ PyTypeObject PyStaticMethod_Type = {
11071114
0, /* tp_as_sequence */
11081115
0, /* tp_as_mapping */
11091116
0, /* tp_hash */
1110-
0, /* tp_call */
1117+
sm_call, /* tp_call */
11111118
0, /* tp_str */
11121119
0, /* tp_getattro */
11131120
0, /* tp_setattro */

0 commit comments

Comments
 (0)