Supposons que j’ai une fonction Python telle que définie ci-dessous:
def foo(arg1,arg2):
#do something with args
a = arg1 + arg2
return a
Je peux obtenir le nom de la fonction en utilisant foo.func_name
. Comment puis-je obtenir par programme son code source, comme j'ai tapé ci-dessus?
Si la fonction provient d'un fichier source disponible sur le système de fichiers, alors inspect.getsource(foo)
peut être utile:
Si foo
est défini comme:
def foo(arg1,arg2):
#do something with args
a = arg1 + arg2
return a
Ensuite:
import inspect
lines = inspect.getsource(foo)
print(lines)
Résultats:
def foo(arg1,arg2):
#do something with args
a = arg1 + arg2
return a
Mais je crois que si la fonction est compilée à partir d'une chaîne, d'un flux ou importée à partir d'un fichier compilé, vous ne pouvez pas récupérer son code source.
Le module d'inspection possède des méthodes permettant de récupérer le code source à partir d'objets python. Apparemment, cela ne fonctionne que si la source est située dans un fichier. Si vous aviez cela, je suppose que vous n'auriez pas besoin d'obtenir la source de l'objet.
dis
est votre ami si le code source n'est pas disponible:
>>> import dis
>>> def foo(arg1,arg2):
... #do something with args
... a = arg1 + arg2
... return a
...
>>> dis.dis(foo)
3 0 LOAD_FAST 0 (arg1)
3 LOAD_FAST 1 (arg2)
6 BINARY_ADD
7 STORE_FAST 2 (a)
4 10 LOAD_FAST 2 (a)
13 RETURN_VALUE
Si vous utilisez IPython, vous devez taper "foo ??"
In [19]: foo??
Signature: foo(arg1, arg2)
Source:
def foo(arg1,arg2):
#do something with args
a = arg1 + arg2
return a
File: ~/Desktop/<ipython-input-18-3174e3126506>
Type: function
Bien que je sois généralement d’accord pour dire que inspect
est une bonne réponse, je ne dirais pas que vous ne pouvez pas obtenir le code source des objets définis dans l’interpréteur. Si vous utilisez dill.source.getsource
de dill
, vous pouvez obtenir la source des fonctions et des lambdas, même s'ils sont définis de manière interactive. Il peut également obtenir le code pour les méthodes et fonctions de classe liées ou non liées définies dans les currys ... Cependant, vous ne pourrez peut-être pas compiler ce code sans le code de l'objet englobant.
>>> from dill.source import getsource
>>>
>>> def add(x,y):
... return x+y
...
>>> squared = lambda x:x**2
>>>
>>> print getsource(add)
def add(x,y):
return x+y
>>> print getsource(squared)
squared = lambda x:x**2
>>>
>>> class Foo(object):
... def bar(self, x):
... return x*x+x
...
>>> f = Foo()
>>>
>>> print getsource(f.bar)
def bar(self, x):
return x*x+x
>>>
Pour développer la réponse de runeh:
>>> def foo(a):
... x = 2
... return x + a
>>> import inspect
>>> inspect.getsource(foo)
u'def foo(a):\n x = 2\n return x + a\n'
print inspect.getsource(foo)
def foo(a):
x = 2
return x + a
EDIT: Comme l'a souligné @ 0sh, cet exemple fonctionne avec ipython
mais pas tout à fait python
. Cela devrait cependant convenir dans les deux cas lors de l'importation de code à partir de fichiers source.
Vous pouvez utiliser le module inspect
pour obtenir le code source complet. Pour cela, vous devez utiliser la méthode getsource()
à partir du module inspect
. Par exemple:
import inspect
def get_my_code():
x = "abcd"
return x
print(inspect.getsource(get_my_code))
Vous pouvez vérifier plus d'options sur le lien ci-dessous. récupère votre python code
Puisque cet article est marqué comme le duplicata de cet autre article , je réponds ici pour le cas "lambda", bien que le PO ne concerne pas lambdas.
Donc, pour les fonctions lambda qui ne sont pas définies dans leurs propres lignes: en plus de la réponse de marko.ristin , vous souhaiterez peut-être utiliser mini-lambda ou utiliser - SymPy comme suggéré dans cette réponse .
mini-lambda
est plus léger et supporte tout type d'opération, mais ne fonctionne que pour une seule variableSymPy
est plus lourd mais beaucoup plus équipé d'opérations mathématiques/calcul. En particulier, cela peut simplifier vos expressions. Il prend également en charge plusieurs variables dans la même expression.Voici comment vous pouvez le faire en utilisant mini-lambda
:
from mini_lambda import x, is_mini_lambda_expr
import inspect
def get_source_code_str(f):
if is_mini_lambda_expr(f):
return f.to_string()
else:
return inspect.getsource(f)
# test it
def foo(arg1, arg2):
# do something with args
a = arg1 + arg2
return a
print(get_source_code_str(foo))
print(get_source_code_str(x ** 2))
Il cède correctement
def foo(arg1, arg2):
# do something with args
a = arg1 + arg2
return a
x ** 2
Voir mini-lambda
documentation pour plus de détails. Je suis l'auteur au fait;)
résumer :
import inspect
print( "".join(inspect.getsourcelines(foo)[0]))
Si vous définissez strictement la fonction vous-même et qu'il s'agit d'une définition relativement courte, une solution sans dépendances serait de définir la fonction dans une chaîne et d'affecter l'eval () de l'expression à votre fonction.
Par exemple.
funcstring = 'lambda x: x> 5'
func = eval(funcstring)
puis optionnellement pour attacher le code original à la fonction:
func.source = funcstring
Veuillez noter que les réponses acceptées ne fonctionnent que si le lambda est donné sur une ligne séparée. Si vous le transmettez en tant qu'argument à une fonction et souhaitez récupérer le code du lambda en tant qu'objet, le problème devient un peu délicat puisque inspect
vous donnera la ligne entière.
Par exemple, considérons un fichier test.py
:
import inspect
def main():
x, f = 3, lambda a: a + 1
print(inspect.getsource(f))
if __== "__main__":
main()
L'exécuter vous donne (attention à la rétention!):
x, f = 3, lambda a: a + 1
Pour récupérer le code source du lambda, votre meilleur choix, à mon avis, est de ré-analyser tout le fichier source (en utilisant f.__code__.co_filename
) et de faire correspondre le noeud lambda AST à la ligne. nombre et son contexte.
Nous devions faire exactement cela dans notre bibliothèque conception par contrat icontract car nous devions analyser les fonctions lambda que nous transmettons comme arguments aux décorateurs. C'est trop de code à coller ici, alors jetez un oeil à l'implémentation de cette fonction .
Si vous utilisez IPython, une autre option consiste à utiliser ??
après le nom de la fonction pour afficher son code source. Voici un exemple:
[nav] In [1]: def foo(arg1,arg2):
...: #do something with args
...: a = arg1 + arg2
...: return a
[nav] In [2]: foo??
Signature: foo(arg1, arg2)
Docstring: <no docstring>
Source:
def foo(arg1,arg2):
#do something with args
a = arg1 + arg2
return a
Je crois que les noms de variables ne sont pas stockés dans les fichiers pyc/pyd/pyo, vous ne pouvez donc pas récupérer les lignes de code exactes si vous n'avez pas de fichiers source.