Skip to content

GH-132341: Implement the identity function in the operator module #132342

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Doc/library/operator.rst
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,13 @@ expect a function argument.
return caller


.. function:: identity(obj, /)

Returns *obj* unchanged.

.. versionadded:: next


.. _operator-map:

Mapping Operators to Functions
Expand Down
6 changes: 5 additions & 1 deletion Lib/operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

__all__ = ['abs', 'add', 'and_', 'attrgetter', 'call', 'concat', 'contains', 'countOf',
'delitem', 'eq', 'floordiv', 'ge', 'getitem', 'gt', 'iadd', 'iand',
'iconcat', 'ifloordiv', 'ilshift', 'imatmul', 'imod', 'imul',
'iconcat', 'identity', 'ifloordiv', 'ilshift', 'imatmul', 'imod', 'imul',
'index', 'indexOf', 'inv', 'invert', 'ior', 'ipow', 'irshift',
'is_', 'is_none', 'is_not', 'is_not_none', 'isub', 'itemgetter', 'itruediv',
'ixor', 'le', 'length_hint', 'lshift', 'lt', 'matmul', 'methodcaller', 'mod',
Expand Down Expand Up @@ -231,6 +231,10 @@ def length_hint(obj, default=0):

# Other Operations ************************************************************#

def identity(obj, /):
"""Return the argument unchanged."""
return obj

def call(obj, /, *args, **kwargs):
"""Same as obj(*args, **kwargs)."""
return obj(*args, **kwargs)
Expand Down
21 changes: 21 additions & 0 deletions Lib/test/test_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,27 @@ class Y: pass
operator.length_hint(X(2), "abc")
self.assertEqual(operator.length_hint(Y(), 10), 10)

def test_identity(self):
operator = self.module
a = 'spam'
b = []
b.append(b)
c = None
d = object()
try:
1/0
except ZeroDivisionError as exc:
e = exc
f = {a, c, d, 'ham' * 1000}

self.assertRaises(TypeError, operator.identity)
self.assertIs(operator.identity(a), a)
self.assertIs(operator.identity(b), b)
self.assertIs(operator.identity(c), c)
self.assertIs(operator.identity(d), d)
self.assertIs(operator.identity(e), e)
self.assertIs(operator.identity(f), f)

def test_call(self):
operator = self.module

Expand Down
8 changes: 0 additions & 8 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -7868,14 +7868,6 @@ def foo(a: A) -> Optional[BaseException]:
self.assertIsNone(foo(None))


class TestModules(TestCase):
func_names = ['_idfunc']

def test_c_functions(self):
for fname in self.func_names:
self.assertEqual(getattr(typing, fname).__module__, '_typing')


class NewTypeTests(BaseTestCase):
@classmethod
def setUpClass(cls):
Expand Down
3 changes: 1 addition & 2 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
from types import GenericAlias

from _typing import (
_idfunc,
TypeVar,
ParamSpec,
TypeVarTuple,
Expand Down Expand Up @@ -3359,7 +3358,7 @@ def name_by_id(user_id: UserId) -> str:
num = UserId(5) + 1 # type: int
"""

__call__ = _idfunc
__call__ = operator.identity

def __init__(self, name, tp):
self.__qualname__ = name
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add :func:`operator.identity`, the identity function.
Patch by Adam Turner.
17 changes: 17 additions & 0 deletions Modules/_operator.c
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,22 @@ _operator__compare_digest_impl(PyObject *module, PyObject *a, PyObject *b)
return PyBool_FromLong(rc);
}

/*[clinic input]
_operator.identity -> object

obj: object
/

Return the argument unchanged.
[clinic start generated code]*/

static PyObject *
_operator_identity(PyObject *module, PyObject *obj)
/*[clinic end generated code: output=deede47105fe0dd8 input=72f5a615c2a823c2]*/
{
return Py_NewRef(obj);
}

PyDoc_STRVAR(_operator_call__doc__,
"call($module, obj, /, *args, **kwargs)\n"
"--\n"
Expand Down Expand Up @@ -994,6 +1010,7 @@ static struct PyMethodDef operator_methods[] = {
_OPERATOR_GE_METHODDEF
_OPERATOR__COMPARE_DIGEST_METHODDEF
_OPERATOR_LENGTH_HINT_METHODDEF
_OPERATOR_IDENTITY_METHODDEF
_OPERATOR_CALL_METHODDEF
{NULL, NULL} /* sentinel */

Expand Down
32 changes: 1 addition & 31 deletions Modules/_typingmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,36 +9,6 @@
#include "internal/pycore_typevarobject.h"
#include "internal/pycore_unionobject.h" // _PyUnion_Type
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include "clinic/_typingmodule.c.h"

/*[clinic input]
module _typing

[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=1db35baf1c72942b]*/

/* helper function to make typing.NewType.__call__ method faster */

/*[clinic input]
_typing._idfunc -> object

x: object
/

[clinic start generated code]*/

static PyObject *
_typing__idfunc(PyObject *module, PyObject *x)
/*[clinic end generated code: output=63c38be4a6ec5f2c input=49f17284b43de451]*/
{
return Py_NewRef(x);
}


static PyMethodDef typing_methods[] = {
_TYPING__IDFUNC_METHODDEF
{NULL, NULL, 0, NULL}
};

PyDoc_STRVAR(typing_doc,
"Primitives and accelerators for the typing module.\n");
Expand Down Expand Up @@ -85,7 +55,7 @@ static struct PyModuleDef typingmodule = {
"_typing",
typing_doc,
0,
typing_methods,
NULL,
_typingmodule_slots,
NULL,
NULL,
Expand Down
11 changes: 10 additions & 1 deletion Modules/clinic/_operator.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 0 additions & 12 deletions Modules/clinic/_typingmodule.c.h

This file was deleted.

Loading