Si je déclare deux fonctions a
et b
:
>>> a.__name__ = '<lambda>' >>> is_lambda_function(a) True
je ne peux pas utiliser type
pour les différencier, car ils sont tous les deux du même type.
def is_lambda_function(function): return function.__name__ == "<lambda>" >>> is_lambda_function(a) False >>> is_lambda_function(b) True
De plus, types.LambdaType
n'aide pas:
XXX
On pourrait utiliser __name__
comme:
>>> import types >>> isinstance(a, types.LambdaType) True >>> isinstance(b, types.LambdaType) True
Cependant, puisque __name__
pourrait ont été modifiés, is_lambda_function
n'est pas garanti de retourner le résultat correct:
assert type(a) == type(b)
Y a-t-il un moyen qui produit un résultat plus fiable que le __ name__
attribut?
3 Réponses :
AFAIK, vous ne pouvez pas être fiable en Python 3.
Python 2 utilisé pour définir un tas de types de fonctions. Pour cette raison, les méthodes, les lambdas et les fonctions simples ont chacun leur propre type.
Python 3 n'a qu'un seul type qui est function
. Il existe en effet différents effets secondaires où déclarer une fonction régulière avec def
et un lambda
: def
définit le nom sur le nom (et le nom qualifié) de la fonction et peut définir une docstring, tandis que lambda
définit le nom (et le nom qualifié) sur
, et définit la docstring sur None. Mais comme cela peut être changé ...
Si les fonctions sont chargées depuis une source Python ordinaire (et non tapées dans un environnement interactif), le module inspect
permet d'accéder au code Python original:
>>> g = lambda x: 3*x >>> g.__qualname__ = "g" >>> pickle.dumps(g) b'\x80\x03c__main__\ng\nq\x00.'
Cela affichera:
<function f at 0x00000253957B7840> False <function g at 0x00000253957B78C8> True
Au fait, si le problème était la sérialisation de la fonction, une fonction déclarée comme lambda peut être décapée avec succès, à condition que vous lui donniez un nom qualifié unique:
import inspect def f(x): return x**2 g = lambda x: x**2 def is_lambda_func(f): """Tests whether f was declared as a lambda. Returns: True for a lambda, False for a function or method declared with def Raises: TypeError if f in not a function OSError('could not get source code') if f was not declared in a Python module but (for example) in an interactive session """ if not inspect.isfunction(f): raise TypeError('not a function') src = inspect.getsource(f) return not src.startswith('def') and not src.startswith('@') # provision for decorated funcs g.__name__ = 'g' g.__qualname__ = 'g' print(f, is_lambda_func(f)) print(g, is_lambda_func(g))
J'ai profité de l'occasion pour plonger dans source de cpython pour voir si je pouvais trouver quelque chose, et je J'ai peur de devoir revenir sur la réponse de Serge : vous ne pouvez pas.
En bref, voici le parcours d'un lambda dans l'interprète:
expr_ty
est ensuite convertie dans le type approprié ( Lambda , dans notre cas) De cela, je ne vois rien de particulier qui soit spécifique aux lambdas. Ceci, combiné au fait que Python vous permet de modifier à peu près tous les attributs des objets, me / nous fait croire que ce que vous voulez faire n'est pas possible.
Pour amplifier votre réponse: puisque def
et lambda
produisent des objets indiscernables (d'autant plus que vous pouvez librement modifier __name__
et __qualname__
), non seulement il est "impossible" de faire ce que OP demande, mais ce n'est pas significatif . Comment faire la différence entre une liste produite par une compréhension de liste et une liste créée par la fonction list
et remplie par une boucle for
? Comment faire la différence entre une chaîne produite par des guillemets simples et une chaîne produite par des guillemets doubles? Vous ne pouvez pas, car il n'y a aucune différence , sauf au niveau du code source.
Vous pouvez vérifier __code __. co_name
. Il contient le nom au moment de la compilation de la fonction / lambda:
>>> is_lambda_function(a) False >>> is_lambda_function(b) True
Et, contrairement à __name__
, __code __. Co_name
est en lecture seule ...
>>> a.__name__ = "<lambda>" >>> b.__name__ = "b" >>> a.__code__.co_name = "<lambda>" Traceback (most recent call last): File "<console>", line 1, in <module> AttributeError: readonly attribute >>> b.__code__.co_name = "b" Traceback (most recent call last): File "<console>", line 1, in <module> AttributeError: readonly attribute
... pour que les résultats restent les mêmes:
def a(x): return x**2 b = lambda x: x**2 def is_lambda_function(f): return f.__code__.co_name == "<lambda>" >>> is_lambda_function(a) False >>> is_lambda_function(b) True
Y a-t-il un cas d'utilisation pratique où vous en auriez réellement besoin?
Il peut également y avoir des objets qui ne sont ni mais appelables, et des fonctions intégrées Python.
Avec l'autre commentaire ci-dessus, quelle différence cela fait-il qu'il s'agisse d'un def ou d'un lambda?
@JaredSmith, par exemple Django ne peut pas sérialiser Lambdas.
@jpp: IMHO ce n'est pas un doublon! La réponse acceptée pour l'autre question fait clairement référence à Python2 tandis que Python3 est plus couramment utilisé de nos jours. Et il ne peut pas être appliqué en Python3 ...
@jpp stackoverflow.com/a/23852434/521776 cette réponse s'applique également à py3
Quel est votre cas d'utilisation?
Il est difficile de le savoir sans votre cas d'utilisation, mais vous pouvez probablement éviter cela, c'est-à-dire
essayer
quelque chose qui ne fonctionne qu'avec les fonctions def,sauf
l'exception soulevée spécifique et continuer comme vous vouloir@Kanak Dans ce cas: essayez de le sérialiser avec Django?
En relation: stackoverflow.com/questions/12264834/...