2012-01-05 10 views
107

mi piacerebbe puntare a una funzione che non fa nulla:Esiste una funzione di identità incorporata in python?

def identity(*args) 
    return args 

il mio caso d'uso è qualcosa di simile

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

Certo, avrei potuto usare il identity sopra definito, ma un built -in sarebbe certamente eseguito più velocemente (ed eviterà bug introdotti dal mio).

Apparentemente, map e filter utilizzare l'identità None, ma questo è specifico per le loro implementazioni.

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

Cosa intendi per 'mappa e filtro usa Nessuno per l'identità'? –

+13

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

+6

Controlla il valore restituito. La variabile args sarà una sequenza di (in questo scenario) un valore, quindi omettendo l'asterisco nella dichiarazione o scompattandolo prima di tornare. – Dirk

risposta

68

Facendo qualche ricerca, non c'è nessuno, una caratteristica è stato chiesto in issue 1673203 E da Raymond Hettinger said there won't be:

Meglio lascia che le persone scrivano i propri banali passaporti e rifletti sulla firma e sui costi.

Quindi un modo migliore per farlo è in realtà (a lambda evita di nominare la funzione):

_ = lambda *args: args 
  • vantaggio: prende qualunque numero di parametri
  • svantaggio: il risultato è una scatola versione dei parametri

O

_ = lambda x: x 
  • vantaggio: non cambia il tipo di parametro
  • svantaggio: prende esattamente 1 parametro posizionale
+11

Si noti che questa non è una funzione di identità. – Marcin

+1

@Marcin Grazie per l'osservazione. Ho aggiunto vantaggi/svantaggi dei due per non indurre in errore nessuno. E ora, credo davvero che ci dovrebbe essere stata una funzione integrata che accetta qualsiasi numero di parametri ed è una vera identità :) – rds

+6

Bella risposta. Tuttavia, cosa restituirebbe una funzione di identità vera quando si assumono più parametri? – Marcin

16

tuo funzionerà bene. Quando il numero di parametri è risolvere è possibile utilizzare una funzione anonima come questa:

lambda x: x 
+8

Puoi farlo anche con vararg: 'lambda * args: args'. È davvero una scelta stilistica. – delnan

+0

Mi piace il secondo, dato che richiede un numero qualsiasi di argomenti. – rds

+3

@delnan @rds - la versione '* args' ha un tipo di ritorno diverso, quindi non sono equivalenti nemmeno per il caso a argomento singolo. – Marcin

3

No, non c'è.

Nota che il vostro identity:

  1. equivale a lambda * args: args
  2. sarà casella suoi args - cioè

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

Quindi, si possono usare colori lambda arg: arg se si desidera una funzione di identità vera.

-2

Il thread è piuttosto vecchio. Ma volevo ancora postare questo.

È possibile creare un metodo di identità per argomenti e oggetti. Nell'esempio seguente, ObjOut è un'identità per ObjIn.Tutti gli altri esempi sopra non sono stati trattati 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

questo sembra un riferimento, se quindi, da dove viene? –

+0

@JeffPuckettII Non ho seguito la tua domanda. Stai chiedendo se il nuovo oggetto è un riferimento? – Sud

+0

hai usato l'evidenziazione blockquote per "È possibile costruire un'identità ..." che implica un riferimento da un'altra fonte. Se queste sono le tue parole, allora suggerirei di non evidenziarlo come una citazione. davvero non è un grosso problema. ma se questa è una citazione da un'altra fonte, dovresti includere un riferimento ad essa. –

15

Una funzione identità, come definito nella https://en.wikipedia.org/wiki/Identity_function, prende un singolo argomento e lo restituisce inalterato:

def identity(x): 
    return x 

cosa si sta chiedendo quando dici che vuoi la firma def identity(*args) non è strettamente una funzione di identità, come vuoi che prenda più argomenti. Va bene, ma poi si verifica un problema in quanto le funzioni Python non restituiscono più risultati, quindi è necessario trovare un modo per racchiudere tutti questi argomenti in un valore restituito.

Il modo usuale di restituire "valori multipli" in Python è restituire una tupla dei valori - tecnicamente si tratta di un valore restituito ma può essere utilizzato nella maggior parte dei contesti come se si trattasse di più valori. Ma farlo qui significa che si ottiene

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

e fissare che problema dà rapidamente altre questioni, come le diverse risposte qui hanno dimostrato.

Così, in sintesi, non c'è alcuna funzione identità definita in Python perché:

  1. La definizione formale (una sola funzione argomento) non è poi così utile, ed è banale scrivere.
  2. Estendere la definizione a più argomenti non è ben definito in generale, e si sta molto meglio definendo la propria versione che funziona nel modo in cui è necessario per la propria situazione particolare.

Per il vostro caso preciso,

def dummy_gettext(message): 
    return message 

è quasi certamente ciò che si vuole - una funzione che ha la stessa convenzione di chiamata e di ritorno, gettext.gettext, che restituisce il suo argomento invariata, ed è chiaramente il nome per descrivere cosa fa e dove è destinato ad essere usato. Sarei piuttosto scioccato se le prestazioni fossero una considerazione cruciale qui.

0

stub di funzione singolo argomento

gettext.gettext (esempio caso di utilizzo del PO) accetta singolo argomento, message. Se è necessario uno stub, non è necessario restituire [message] anziché message (def identity(*args): return args). Così sia

_ = lambda message: message 

def _(message): 
    return message 

si adattano perfettamente.

... ma un built-in sarebbe sicuramente più veloce (ed eviterà bug introdotti dal mio).

Gli errori in un caso così banale sono appena rilevanti.A proposito di prestazioni, per esempio, per un argomento di tipo predefinito, dicono str, possiamo usarla come funzione identità (a causa di string interning mantiene anche identità di un oggetto, vedere id nota sotto) e confrontare le prestazioni:

$ 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 

Alcune micro-ottimizzazione sono possibili, ma non sembrano valerne la pena.

test.pyx

cpdef str f(str message): 
    return message 

Poi:

$ 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 funzione di oggetto identità

Questo non deve essere confuso con id funzione built-in che ritorna:

"identità" di un oggetto.

Problemi correlati