mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
bpo-43682: Make staticmethod objects callable (GH-25117)
Static methods (@staticmethod) are now callable as regular functions.
This commit is contained in:
parent
53114ffef1
commit
553ee2781a
7 changed files with 32 additions and 14 deletions
|
@ -1619,8 +1619,9 @@ are always available. They are listed here in alphabetical order.
|
||||||
The ``@staticmethod`` form is a function :term:`decorator` -- see
|
The ``@staticmethod`` form is a function :term:`decorator` -- see
|
||||||
:ref:`function` for details.
|
:ref:`function` for details.
|
||||||
|
|
||||||
A static method can be called either on the class (such as ``C.f()``) or on an instance (such
|
A static method can be called either on the class (such as ``C.f()``) or on
|
||||||
as ``C().f()``).
|
an instance (such as ``C().f()``). Moreover, they can be called as regular
|
||||||
|
functions (such as ``f()``).
|
||||||
|
|
||||||
Static methods in Python are similar to those found in Java or C++. Also see
|
Static methods in Python are similar to those found in Java or C++. Also see
|
||||||
:func:`classmethod` for a variant that is useful for creating alternate class
|
: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.
|
||||||
body and you want to avoid the automatic transformation to instance
|
body and you want to avoid the automatic transformation to instance
|
||||||
method. For these cases, use this idiom::
|
method. For these cases, use this idiom::
|
||||||
|
|
||||||
|
def regular_function():
|
||||||
|
...
|
||||||
|
|
||||||
class C:
|
class C:
|
||||||
builtin_open = staticmethod(open)
|
method = staticmethod(regular_function)
|
||||||
|
|
||||||
For more information on static methods, see :ref:`types`.
|
For more information on static methods, see :ref:`types`.
|
||||||
|
|
||||||
.. versionchanged:: 3.10
|
.. versionchanged:: 3.10
|
||||||
Static methods now inherit the method attributes (``__module__``,
|
Static methods now inherit the method attributes (``__module__``,
|
||||||
``__name__``, ``__qualname__``, ``__doc__`` and ``__annotations__``) and
|
``__name__``, ``__qualname__``, ``__doc__`` and ``__annotations__``),
|
||||||
have a new ``__wrapped__`` attribute.
|
have a new ``__wrapped__`` attribute, and are now callable as regular
|
||||||
|
functions.
|
||||||
|
|
||||||
|
|
||||||
.. index::
|
.. index::
|
||||||
|
|
|
@ -1132,9 +1132,8 @@ Internal types
|
||||||
around any other object, usually a user-defined method object. When a static
|
around any other object, usually a user-defined method object. When a static
|
||||||
method object is retrieved from a class or a class instance, the object actually
|
method object is retrieved from a class or a class instance, the object actually
|
||||||
returned is the wrapped object, which is not subject to any further
|
returned is the wrapped object, which is not subject to any further
|
||||||
transformation. Static method objects are not themselves callable, although the
|
transformation. Static method objects are also callable. Static method
|
||||||
objects they wrap usually are. Static method objects are created by the built-in
|
objects are created by the built-in :func:`staticmethod` constructor.
|
||||||
:func:`staticmethod` constructor.
|
|
||||||
|
|
||||||
Class method objects
|
Class method objects
|
||||||
A class method object, like a static method object, is a wrapper around another
|
A class method object, like a static method object, is a wrapper around another
|
||||||
|
|
|
@ -623,6 +623,7 @@ Other Language Changes
|
||||||
(:func:`@classmethod <classmethod>`) now inherit the method attributes
|
(:func:`@classmethod <classmethod>`) now inherit the method attributes
|
||||||
(``__module__``, ``__name__``, ``__qualname__``, ``__doc__``,
|
(``__module__``, ``__name__``, ``__qualname__``, ``__doc__``,
|
||||||
``__annotations__``) and have a new ``__wrapped__`` attribute.
|
``__annotations__``) and have a new ``__wrapped__`` attribute.
|
||||||
|
Moreover, static methods are now callable as regular functions.
|
||||||
(Contributed by Victor Stinner in :issue:`43682`.)
|
(Contributed by Victor Stinner in :issue:`43682`.)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -91,14 +91,18 @@ class TestDecorators(unittest.TestCase):
|
||||||
getattr(func, attr))
|
getattr(func, attr))
|
||||||
|
|
||||||
self.assertEqual(repr(wrapper), format_str.format(func))
|
self.assertEqual(repr(wrapper), format_str.format(func))
|
||||||
|
return wrapper
|
||||||
self.assertRaises(TypeError, wrapper, 1)
|
|
||||||
|
|
||||||
def test_staticmethod(self):
|
def test_staticmethod(self):
|
||||||
self.check_wrapper_attrs(staticmethod, '<staticmethod({!r})>')
|
wrapper = self.check_wrapper_attrs(staticmethod, '<staticmethod({!r})>')
|
||||||
|
|
||||||
|
# bpo-43682: Static methods are callable since Python 3.10
|
||||||
|
self.assertEqual(wrapper(1), 1)
|
||||||
|
|
||||||
def test_classmethod(self):
|
def test_classmethod(self):
|
||||||
self.check_wrapper_attrs(classmethod, '<classmethod({!r})>')
|
wrapper = self.check_wrapper_attrs(classmethod, '<classmethod({!r})>')
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, wrapper, 1)
|
||||||
|
|
||||||
def test_dotted(self):
|
def test_dotted(self):
|
||||||
decorators = MiscDecorators()
|
decorators = MiscDecorators()
|
||||||
|
|
|
@ -1142,7 +1142,7 @@ class TestDescriptions(unittest.TestCase):
|
||||||
'''A static method'''
|
'''A static method'''
|
||||||
...
|
...
|
||||||
self.assertEqual(self._get_summary_lines(X.__dict__['sm']),
|
self.assertEqual(self._get_summary_lines(X.__dict__['sm']),
|
||||||
'sm(...)\n'
|
'sm(x, y)\n'
|
||||||
' A static method\n')
|
' A static method\n')
|
||||||
self.assertEqual(self._get_summary_lines(X.sm), """\
|
self.assertEqual(self._get_summary_lines(X.sm), """\
|
||||||
sm(x, y)
|
sm(x, y)
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Static methods (:func:`@staticmethod <staticmethod>`) are now callable as
|
||||||
|
regular functions. Patch by Victor Stinner.
|
|
@ -1040,6 +1040,13 @@ sm_init(PyObject *self, PyObject *args, PyObject *kwds)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject*
|
||||||
|
sm_call(PyObject *callable, PyObject *args, PyObject *kwargs)
|
||||||
|
{
|
||||||
|
staticmethod *sm = (staticmethod *)callable;
|
||||||
|
return PyObject_Call(sm->sm_callable, args, kwargs);
|
||||||
|
}
|
||||||
|
|
||||||
static PyMemberDef sm_memberlist[] = {
|
static PyMemberDef sm_memberlist[] = {
|
||||||
{"__func__", T_OBJECT, offsetof(staticmethod, sm_callable), READONLY},
|
{"__func__", T_OBJECT, offsetof(staticmethod, sm_callable), READONLY},
|
||||||
{"__wrapped__", T_OBJECT, offsetof(staticmethod, sm_callable), READONLY},
|
{"__wrapped__", T_OBJECT, offsetof(staticmethod, sm_callable), READONLY},
|
||||||
|
@ -1107,7 +1114,7 @@ PyTypeObject PyStaticMethod_Type = {
|
||||||
0, /* tp_as_sequence */
|
0, /* tp_as_sequence */
|
||||||
0, /* tp_as_mapping */
|
0, /* tp_as_mapping */
|
||||||
0, /* tp_hash */
|
0, /* tp_hash */
|
||||||
0, /* tp_call */
|
sm_call, /* tp_call */
|
||||||
0, /* tp_str */
|
0, /* tp_str */
|
||||||
0, /* tp_getattro */
|
0, /* tp_getattro */
|
||||||
0, /* tp_setattro */
|
0, /* tp_setattro */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue