web-dev-qa-db-fra.com

Comment puis-je obtenir le code source d'une fonction Python?

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?

348
david

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.

478
Rafał Dowgird

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.

177
runeh

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
79
schlamar

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
69
prashanth

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

>>> 
56
Mike McKerns

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.

21
TomDotTom

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

11
Krutarth Gor

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 variable
  • SymPy 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-lambdadocumentation pour plus de détails. Je suis l'auteur au fait;)

4
smarie

résumer :

import inspect
print( "".join(inspect.getsourcelines(foo)[0]))
4
douardo

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
3
cherplunk

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 .

2
marko.ristin

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
1
Aziz Alto

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.

0
Abgan