2012-01-05 8 views
107

me gustaría apuntar a una función que no hace nada:¿Hay una función de identidad integrada en python?

def identity(*args) 
    return args 

mi caso de uso es algo como esto

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

Por supuesto, podría utilizar el identity definido anteriormente, pero un sistema incorporado - ciertamente correría más rápido (y evitaría errores introducidos por mi cuenta).

Al parecer, map y filter usan None para la identidad, pero esto es específico de sus implementaciones.

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

¿Qué quiere decir con 'map and filter use None for the identity'? –

+13

@MattFenwick: 'map (None, [1, 2, 3])' –

+6

Compruebe el valor de retorno. Su variable args será una secuencia de (en este escenario) un valor, por lo tanto, omita el asterisco en la declaración, o descomprímalo antes de regresar. – Dirk

Respuesta

68

Haciendo un poco más investigación, no hay ninguno, una característica se le preguntó en issue 1673203 Y desde Raymond Hettinger said there won't be:

Mejor deje que las personas escriban sus propios pases triviales y piense en los costos de firma y tiempo.

lo tanto una mejor manera de hacerlo es en realidad (una lambda evita nombrar a la función):

_ = lambda *args: args 
  • ventaja: toma cualquier número de parámetros
  • desventaja: el resultado es una caja versión de los parámetros

O

_ = lambda x: x 
  • ventaja: no cambia el tipo del parámetro
  • desventaja: toma exactamente 1 parámetro posicional
+11

Tenga en cuenta que esto no es una función de identidad. – Marcin

+1

@Marcin Gracias por el comentario. He agregado ventajas/inconvenientes de los dos para no engañar a nadie. Y ahora, realmente creo que debería haber una función incorporada que acepta cualquier número de parámetros y es una verdadera identidad :) – rds

+6

Nice answer. Sin embargo, ¿qué devolvería una verdadera función de identidad al tomar múltiples parámetros? – Marcin

16

tuyo funcionará bien. Cuando el número de parámetros es fijar puede utilizar una función anónima como esto:

lambda x: x 
+8

También puede hacer esto con varargs: 'lambda * args: args'. Es realmente una elección estilística. – delnan

+0

Me gusta el segundo mejor, ya que toma cualquier cantidad de argumentos. – rds

+3

@delnan @rds: la versión '* args' tiene un tipo de devolución diferente, por lo que no son equivalentes ni siquiera para el caso de argumento único. – Marcin

3

No, no lo hay.

en cuenta que su identity:

  1. es equivalente a lambda * args: args
  2. encajonará sus argumentos - es decir

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

Por lo tanto, es posible que desee utilizar lambda arg: arg si quieres una verdadera función de identidad.

-2

El hilo es bastante antiguo. Pero todavía quería publicar esto.

Es posible construir un método de identidad para ambos argumentos y objetos. En el siguiente ejemplo, ObjOut es una identidad para ObjIn.Todos los demás ejemplos anteriores no han tratado con 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} 
+0

esto parece una referencia, si Entonces, ¿de dónde es? –

+0

@JeffPuckettII No seguí tu pregunta. ¿Estás preguntando si el nuevo objeto es una referencia? – Sud

+0

usaste un destacado de bloque para "Es posible construir una identidad ..." que implica una referencia de otra fuente. Si estas son tus propias palabras, te sugiero que no lo destaques como una cita. realmente no es un gran problema. pero si esta es una cita de otra fuente, entonces debe incluir una referencia a ella. –

15

Una función identidad, como se define en https://en.wikipedia.org/wiki/Identity_function, toma un solo argumento y devuelve sin cambios:

def identity(x): 
    return x 

lo que están pidiendo para cuando usted dice que quiere la firma def identity(*args) es no estrictamente una función de identidad, ya que quiere que tome múltiples argumentos. Está bien, pero luego se produce un problema ya que las funciones de Python no devuelven resultados múltiples, por lo que debe encontrar la manera de agrupar todos esos argumentos en un valor de retorno.

La forma habitual de devolver "valores múltiples" en Python es devolver una tupla de los valores, técnicamente ese es un valor de retorno, pero se puede usar en la mayoría de los contextos como si se tratara de valores múltiples. Pero hacer eso aquí significa que usted obtiene

>>> 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,) 

y la fijación de un problema que rápidamente da otras cuestiones, como las diversas respuestas aquí han demostrado.

Así, en resumen, no hay ninguna función identidad definida en Python porque:

  1. La definición formal (una sola función argumento) no es tan útil, y es trivial para escribir.
  2. ampliar el concepto a varios argumentos no está bien definido, en general, y ya está mucho mejor definición de su propia versión que funciona de la manera que lo necesite para su situación particular.

Para su caso preciso,

def dummy_gettext(message): 
    return message 

es casi seguro que lo que quiere - una función que tiene la misma convención de llamada y la de regreso si lo gettext.gettext, que devuelve su argumento sin cambios, y está claramente nombrado para describir qué hace y dónde está destinado a ser utilizado. Estaría bastante sorprendido si el rendimiento fuera una consideración crucial aquí.

0

Stub de la función de un solo argumento

gettext.gettext (ejemplo de caso de uso de la OP) acepta solo argumento, message. Si necesita un talón, no hay razón para devolver [message] en lugar de message (def identity(*args): return args). Por lo tanto, ambos

_ = lambda message: message 

def _(message): 
    return message 

encajan perfectamente.

... pero un built-in ciertamente funcionaría más rápido (y evitaría errores introducidos por mi cuenta).

Los errores en un caso tan trivial son apenas relevantes.Sobre el rendimiento, por ejemplo, para un argumento de tipo predefinido, dicen str, podemos usarlo como una función de identidad (debido a string interning aún conserva la identidad del objeto, consulte id nota más abajo) y comparar el rendimiento:

$ 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 

Algunas micro-optimizaciones son posibles, pero no parecen valer la pena.

test.pyx

cpdef str f(str message): 
    return message 

continuación:

$ 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 

Construir-en función de la identidad del objeto

Esto no debe confundirse con id función incorporada que devuelve:

la "identidad" de un objeto.

Cuestiones relacionadas