Is there a builtin identity function in python?

Question:

I’d like to point to a function that does nothing:

def identity(*args)
    return args

my use case is something like this

try:
    gettext.find(...)
    ...
    _ = gettext.gettext
else:
    _ = identity

Of course, I could use the identity defined above, but a built-in would certainly run faster (and avoid bugs introduced by my own).

Apparently, map and filter use None for the identity, but this is specific to their implementations.

>>> _=None
>>> _("hello")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable
Asked By: rds

||

Answers:

yours will work fine. When the number of parameters is fix you can use an anonymous function like this:

lambda x: x
Answered By: tback

Doing some more research, there is none, a feature was asked in issue 1673203 And from Raymond Hettinger said there won’t be:

Better to let people write their own trivial pass-throughs
and think about the signature and time costs.

So a better way to do it is actually (a lambda avoids naming the function):

_ = lambda *args: args
  • advantage: takes any number of parameters
  • disadvantage: the result is a boxed version of the parameters

OR

_ = lambda x: x
  • advantage: doesn’t change the type of the parameter
  • disadvantage: takes exactly 1 positional parameter
Answered By: rds

No, there isn’t.

Note that your identity:

  1. is equivalent to lambda *args: args
  2. Will box its args – i.e.

    In [6]: id = lambda *args: args
    
    In [7]: id(3)
    Out[7]: (3,)
    

So, you may want to use lambda arg: arg if you want a true identity function.

NB: This example will shadow the built-in id function (which you will probably never use).

Answered By: Marcin

The thread is pretty old. But still wanted to post this.

It is possible to build an identity method for both arguments and objects. In the example below, ObjOut is an identity for ObjIn. All other examples above haven’t dealt with dict **kwargs.

class test(object):
    def __init__(self,*args,**kwargs):
        self.args = args
        self.kwargs = kwargs
    def identity (self):
        return self

objIn=test('arg-1','arg-2','arg-3','arg-n',key1=1,key2=2,key3=3,keyn='n')
objOut=objIn.identity()
print('args=',objOut.args,'kwargs=',objOut.kwargs)

#If you want just the arguments to be printed...
print(test('arg-1','arg-2','arg-3','arg-n',key1=1,key2=2,key3=3,keyn='n').identity().args)
print(test('arg-1','arg-2','arg-3','arg-n',key1=1,key2=2,key3=3,keyn='n').identity().kwargs)

$ py test.py
args= ('arg-1', 'arg-2', 'arg-3', 'arg-n') kwargs= {'key1': 1, 'keyn': 'n', 'key2': 2, 'key3': 3}
('arg-1', 'arg-2', 'arg-3', 'arg-n')
{'key1': 1, 'keyn': 'n', 'key2': 2, 'key3': 3}
Answered By: Sud

An identity function, as defined in https://en.wikipedia.org/wiki/Identity_function, takes a single argument and returns it unchanged:

def identity(x):
    return x

What you are asking for when you say you want the signature def identity(*args) is not strictly an identity function, as you want it to take multiple arguments. That’s fine, but then you hit a problem as Python functions don’t return multiple results, so you have to find a way of cramming all of those arguments into one return value.

The usual way of returning “multiple values” in Python is to return a tuple of the values – technically that’s one return value but it can be used in most contexts as if it were multiple values. But doing that here means you get

>>> def mv_identity(*args):
...     return args
...
>>> mv_identity(1,2,3)
(1, 2, 3)
>>> # So far, so good. But what happens now with single arguments?
>>> mv_identity(1)
(1,)

And fixing that problem quickly gives other issues, as the various answers here have shown.

So, in summary, there’s no identity function defined in Python because:

  1. The formal definition (a single argument function) isn’t that useful, and is trivial to write.
  2. Extending the definition to multiple arguments is not well-defined in general, and you’re far better off defining your own version that works the way you need it to for your particular situation.

For your precise case,

def dummy_gettext(message):
    return message

is almost certainly what you want – a function that has the same calling convention and return as gettext.gettext, which returns its argument unchanged, and is clearly named to describe what it does and where it’s intended to be used. I’d be pretty shocked if performance were a crucial consideration here.

Answered By: Paul Moore

Stub of a single-argument function

gettext.gettext (the OP’s example use case) accepts a single argument, message. If one needs a stub for it, there’s no reason to return [message] instead of message (def identity(*args): return args). Thus both

_ = lambda message: message

def _(message):
    return message

fit perfectly.

…but a built-in would certainly run faster (and avoid bugs introduced by my own).

Bugs in such a trivial case are barely relevant. For an argument of predefined type, say str, we can use str() itself as an identity function (because of string interning it even retains object identity, see id note below) and compare its performance with the lambda solution:

$ python3 -m timeit -s "f = lambda m: m" "f('foo')"
10000000 loops, best of 3: 0.0852 usec per loop
$ python3 -m timeit "str('foo')"
10000000 loops, best of 3: 0.107 usec per loop

A micro-optimisation is possible. For example, the following Cython code:

test.pyx

cpdef str f(str message):
    return message

Then:

$ pip install runcython3
$ makecython3 test.pyx
$ python3 -m timeit -s "from test import f" "f('foo')"
10000000 loops, best of 3: 0.0317 usec per loop

Build-in object identity function

Don’t confuse an identity function with the id built-in function which returns the ‘identity’ of an object (meaning a unique identifier for that particular object rather than that object’s value, as compared with == operator), its memory address in CPython.

Answered By: saaj

There is no a built-in identity function in Python. An imitation of the Haskell’s id function would be:

identity = lambda x, *args: (x,) + args if args else x

Example usage:

identity(1)
1
identity(1,2)
(1, 2)

Since identity does nothing except returning the given arguments, I do not think that it is slower than a native implementation would be.

Answered By: SergiyKolesnikov

If the speed does not matter, this should handle all cases:

def identity(*args, **kwargs):
    if not args:
        if not kwargs:
            return None
        elif len(kwargs) == 1:
            return  next(iter(kwargs.values()))
        else:
            return (*kwargs.values(),)
    elif not kwargs:
        if len(args) == 1:
            return args[0]
        else:
            return args
    else:
        return (*args, *kwargs.values())

Examples of usage:

print(identity())
None
$identity(1)
1
$ identity(1, 2)
(1, 2)
$ identity(1, b=2)
(1, 2)
$ identity(a=1, b=2)
(1, 2)
$ identity(1, 2, c=3)
(1, 2, 3)
Answered By: Binyan Hu

Adding to all answers:

Notice there is an implicit convention in Python stdlib, where a HOF defaulting it’s key parameter function to the identity function, interprets None as such.

E.g. sorted, heapq.merge, max, min, etc.

So, it is not bad idea to consider your HOF expecting key to following the same pattern.

That is, instead of:

def my_hof(x, key=lambda _: _):
   ...

(whis is totally right)

You could write:

def my_hof(x, key=None):
    if key is None: key = lambda _: _
    ...

If you want.

Answered By: jgomo3

Lots of good answers and discussion are in this topic. I just want to note that, in OP’s case where there is a single argument in the identity function, compile-wise it doesn’t matter if you use a lambda or define a function (in which case you should probably define the function to stay PEP8 compliant). The bytecodes are functionally identical:

import dis
function_method = compile("def identity(x):n    return xny=identity(Type('x', (), dict()))", "foo", "exec")
dis.dis(function_method)
  1           0 LOAD_CONST               0 (<code object identity at 0x7f52cc30b030, file "foo", line 1>)
              2 LOAD_CONST               1 ('identity')
              4 MAKE_FUNCTION            0
              6 STORE_NAME               0 (identity)

  3           8 LOAD_NAME                0 (identity)
             10 LOAD_NAME                1 (Type)
             12 LOAD_CONST               2 ('x')
             14 LOAD_CONST               3 (())
             16 LOAD_NAME                2 (dict)
             18 CALL_FUNCTION            0
             20 CALL_FUNCTION            3
             22 CALL_FUNCTION            1
             24 STORE_NAME               3 (y)
             26 LOAD_CONST               4 (None)
             28 RETURN_VALUE

Disassembly of <code object identity at 0x7f52cc30b030, file "foo", line 1>:
  2           0 LOAD_FAST                0 (x)
              2 RETURN_VALUE

And lambda

import dis
lambda_method = compile("identity = lambda x: xny=identity(Type('x', (), dict()))", "foo", "exec")
dis.dis(lambda_method)
  1           0 LOAD_CONST               0 (<code object <lambda> at 0x7f52c9fbbd20, file "foo", line 1>)
              2 LOAD_CONST               1 ('<lambda>')
              4 MAKE_FUNCTION            0
              6 STORE_NAME               0 (identity)

  2           8 LOAD_NAME                0 (identity)
             10 LOAD_NAME                1 (Type)
             12 LOAD_CONST               2 ('x')
             14 LOAD_CONST               3 (())
             16 LOAD_NAME                2 (dict)
             18 CALL_FUNCTION            0
             20 CALL_FUNCTION            3
             22 CALL_FUNCTION            1
             24 STORE_NAME               3 (y)
             26 LOAD_CONST               4 (None)
             28 RETURN_VALUE

Disassembly of <code object <lambda> at 0x7f52c9fbbd20, file "foo", line 1>:
  1           0 LOAD_FAST                0 (x)
              2 RETURN_VALUE
Answered By: Andrew Holmgren
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.