Как я могу получить исходный код функции Python? - PullRequest
334 голосов
/ 09 января 2009

Предположим, у меня есть функция Python, как указано ниже:

def foo(arg1,arg2):
    #do something with args
    a = arg1 + arg2
    return a

Я могу получить название функции, используя foo.func_name. Как программно получить исходный код, как я напечатал выше?

Ответы [ 13 ]

462 голосов
/ 09 января 2009

Если функция из исходного файла, доступного в файловой системе, тогда может помочь inspect.getsource(foo):

Если foo определяется как:

def foo(arg1,arg2):         
    #do something with args 
    a = arg1 + arg2         
    return a  

Тогда:

import inspect
lines = inspect.getsource(foo)
print(lines)

Возвращает:

def foo(arg1,arg2):         
    #do something with args 
    a = arg1 + arg2         
    return a                

Но я считаю, что если функция скомпилирована из строки, потока или импортирована из скомпилированного файла, вы не сможете получить ее исходный код.

176 голосов
/ 09 января 2009

В модуле inspect есть методы для получения исходного кода из объектов Python. По-видимому, это работает только в том случае, если источник находится в файле. Если бы у вас было это, я думаю, вам не нужно было бы получать источник от объекта.

79 голосов
/ 28 июня 2013

dis ваш друг, если исходный код недоступен:

>>> 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
65 голосов
/ 09 мая 2016

Если вы используете IPython, вам нужно набрать "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
55 голосов
/ 24 января 2014

Хотя я в целом согласен с тем, что inspect - хороший ответ, я не согласен с тем, что вы не можете получить исходный код объектов, определенных в интерпретаторе. Если вы используете dill.source.getsource из dill, вы можете получить источник функций и лямбд, даже если они определены интерактивно. Он также может получить код для связанных или несвязанных методов и функций класса, определенных в карри ... однако вы не сможете скомпилировать этот код без кода вмещающего объекта.

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

>>> 
21 голосов
/ 03 августа 2014

Чтобы расширить ответ Руны:

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

РЕДАКТИРОВАТЬ: Как указывает @ 0sh, этот пример работает с использованием ipython, но не простым python. Однако при импорте кода из исходных файлов все должно быть в порядке.

10 голосов
/ 09 июля 2017

Вы можете использовать модуль inspect, чтобы получить полный исходный код для этого. Для этого вы должны использовать метод getsource() из модуля inspect. Например:

import inspect

def get_my_code():
    x = "abcd"
    return x

print(inspect.getsource(get_my_code))

Вы можете проверить другие варианты по ссылке ниже. получить ваш код Python

4 голосов
/ 03 января 2017

Подведем итог:

import inspect
print( "".join(inspect.getsourcelines(foo)[0]))
3 голосов
/ 17 апреля 2012

Если вы строго определяете функцию самостоятельно и это относительно короткое определение, решение без зависимостей будет состоять в том, чтобы определить функцию в строке и присвоить eval () выражения вашей функции.

например.

funcstring = 'lambda x: x> 5'
func = eval(funcstring)

, а затем при желании присоединить исходный код к функции:

func.source = funcstring
2 голосов
/ 14 сентября 2018

Обратите внимание, что принятые ответы работают только в том случае, если лямбда дана в отдельной строке. Если вы передадите его в качестве аргумента функции и захотите извлечь код лямбда-выражения как объект, проблема будет немного хитрой, поскольку inspect даст вам всю строку.

Например, рассмотрим файл test.py:

import inspect

def main():
    x, f = 3, lambda a: a + 1
    print(inspect.getsource(f))

if __name__ == "__main__":
    main()

Выполнение этого дает вам (помните абзац!):

    x, f = 3, lambda a: a + 1

Чтобы получить исходный код лямбды, лучше всего, по моему мнению, повторно проанализировать весь исходный файл (используя f.__code__.co_filename) и сопоставить лямбда-узел AST по номеру строки и ее контексту.

Мы должны были сделать именно это в нашей библиотеке проектирования по контракту icontract , поскольку нам пришлось анализировать лямбда-функции, которые мы передаем в качестве аргументов декораторам. Здесь слишком много кода для вставки, поэтому взгляните на реализацию этой функции .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...