web-dev-qa-db-fra.com

Existe-t-il une fonction d'identité intégrée en python?

Je voudrais signaler une fonction qui ne fait rien:

def identity(*args)
    return args

mon cas d'utilisation est quelque chose comme ça

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

Bien sûr, je pourrais utiliser le identity défini ci-dessus, mais une fonction intégrée serait certainement plus rapide (et éviterait les bugs introduits par moi-même).

Apparemment, map et filter utilisent None pour l'identité, mais cela est spécifique à leurs implémentations.

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

Pour faire d'autres recherches, il n'y en a pas, une fonctionnalité a été posée dans numéro 16732 Et à partir de Raymond Hettinger a dit qu'il n'y en aura pas :

Mieux vaut laisser les gens écrire leurs propres transitions triviales et réfléchir aux coûts de signature et de temps.

Donc, une meilleure façon de le faire est réellement (un lambda évite de nommer la fonction):

_ = lambda *args: args
  • avantage: prend n'importe quel nombre de paramètres
  • inconvénient: le résultat est une version encadrée des paramètres

OR

_ = lambda x: x
  • avantage: ne change pas le type du paramètre
  • inconvénient: prend exactement 1 paramètre de position
89
rds

Une fonction d'identité, telle que définie dans https://en.wikipedia.org/wiki/Identity_function , prend un seul argument et le renvoie tel quel:

def identity(x):
    return x

Ce que vous demandez lorsque vous dites que vous voulez que la signature def identity(*args) ne soit pas strictement une fonction d’identité, telle que vous la souhaitez. arguments multiples. Bien, mais vous rencontrez un problème comme Python ne renvoient pas plusieurs résultats. Vous devez donc trouver un moyen de regrouper tous ces arguments dans une seule valeur de retour.

Le moyen habituel de renvoyer des "valeurs multiples" dans Python est de renvoyer un tuple des valeurs - techniquement, il s'agit d'une valeur de retour, mais il peut être utilisé dans la plupart des contextes comme s'il s'agissait de valeurs multiples. faire cela signifie que vous obtenez

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

Et régler ce problème pose rapidement d’autres problèmes, comme l’ont montré les différentes réponses données ici.

Donc, en résumé, il n'y a pas de fonction d'identité définie dans Python parce que:

  1. La définition formelle (fonction à un seul argument) n’est pas très utile et son écriture est simple.
  2. L'extension de la définition à plusieurs arguments n'est pas bien définie en général, et vous feriez mieux de définir votre propre version qui fonctionne comme vous en avez besoin pour votre situation particulière.

Pour votre cas précis,

def dummy_gettext(message):
    return message

est presque certainement ce que vous voulez - une fonction qui a la même convention d’appel et renvoie comme gettext.gettext, qui retourne son argument sous forme inchangée, et qui est clairement nommée pour décrire ce qu’elle fait et où elle est destinée. Je serais assez choqué si la performance était une considération cruciale ici.

22
Paul Moore

le vôtre fonctionnera bien. Lorsque le nombre de paramètres est correct, vous pouvez utiliser une fonction anonyme comme celle-ci:

lambda x: x
18
tback

Non, il n'y en a pas.

Notez que votre identity:

  1. est équivalent à lambda * args: args
  2. Will box ses arguments - c'est-à-dire.

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

Donc, vous voudrez peut-être utiliser lambda arg: arg _ si vous voulez une vraie fonction d’identité.

NB: Cet exemple va masquer la fonction intégrée id (que vous n'utiliserez probablement jamais).

5
Marcin

Il n’existe pas de fonction d’identité intégrée en Python. Une imitation de la fonction id de Haskell serait:

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

Exemple d'utilisation:

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

Puisque identity ne fait rien, à part le renvoi des arguments donnés, je ne pense pas que ce soit plus lent qu'une implémentation native. Cela peut même être plus rapide, car cela enregistre un appel à une fonction native.

2
SergiyKolesnikov

Stub d'une fonction à un seul argument

gettext.gettext (l'exemple d'utilisation du PO) accepte un seul argument, message. Si on a besoin d'un talon pour cela, il n'y a aucune raison de renvoyer [message] Au lieu de message (def identity(*args): return args). Ainsi les deux

_ = lambda message: message

def _(message):
    return message

s'adapter parfaitement.

... mais une fonction intégrée serait certainement plus rapide (et éviterait les bugs introduits par moi-même).

Les bugs dans un cas aussi trivial sont à peine pertinents. Pour un argument de type prédéfini, par exemple str, nous pouvons utiliser str() elle-même en tant que fonction d'identité (à cause de chaîne interning elle conserve même l'identité de l'objet, voir id note ci-dessous) et comparez ses performances avec la solution lambda:

$ 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

Une micro-optimisation est possible. Par exemple, le code Cython suivant:

test.pyx

cpdef str f(str message):
    return message

Ensuite:

$ 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

Fonction d'identité d'objet intégrée

Ne confondez pas une fonction d'identité avec la fonction intégrée id qui renvoie l'identité d'un objet (signifiant un identifiant unique pour cet objet particulier plutôt que la valeur de cet objet, par rapport à l'opérateur ==), son adresse mémoire en CPython.

1
saaj