Как получить исходный код функции Python?
Предположим, что у меня есть функция Python, как определено ниже:
def foo(arg1,arg2):
#do something with args
a = arg1 + arg2
return a
Я могу получить имя функции, используя foo.func_name
. Как я могу программно получить исходный код, как я набрал выше?
Ответы
Ответ 1
Если функция принадлежит исходному файлу, доступному в файловой системе, то для inspect.getsource(foo)
может потребоваться 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
Но я считаю, что если функция скомпилирована из строки, потока или импортирована из скомпилированного файла, то вы не сможете получить исходный код.
Ответ 2
В проверять модуль есть методы для извлечения исходного кода из объектов python. По-видимому, он работает только в том случае, если источник находится в файле. Если бы у вас было это, я думаю, вам не нужно было бы получать источник из объекта.
Ответ 3
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
Ответ 4
Если вы используете 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
Ответ 5
Хотя я обычно соглашаюсь с тем, что 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
>>>
Ответ 6
Чтобы развернуть ответ 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: Как указано в @0sh, этот пример работает с использованием ipython
, но не является простым python
. Однако при импорте кода из исходных файлов должно быть хорошо в обоих.
Ответ 7
Вы можете использовать модуль inspect
, чтобы получить полный исходный код для этого. Вы должны использовать метод getsource()
для этого из модуля inspect
. Например:
import inspect
def get_my_code():
x = "abcd"
return x
print(inspect.getsource(get_my_code))
Вы можете проверить дополнительные параметры в приведенной ниже ссылке.
получить код python
Ответ 8
:
import inspect
print( "".join(inspect.getsourcelines(foo)[0]))
Ответ 9
Если вы строго определяете функцию самостоятельно и это относительно короткое определение, решение без зависимостей должно определять функцию в строке и присваивать eval() выражения вашей функции.
например.
funcstring = 'lambda x: x> 5'
func = eval(funcstring)
а затем, при желании, прикрепить исходный код к функции:
func.source = funcstring
Ответ 10
Имейте в виду, что принятые ответы работают только в том случае, если лямбда указана на отдельной строке. Если вы передадите его в качестве аргумента функции и хотите получить код лямбда в качестве объекта, проблема будет немного сложной, так как 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 с номером строки и ее контекстом.
Мы должны были сделать именно это в нашей библиотеке по умолчанию, поскольку мы должны были анализировать функции лямбда, которые мы передаем в качестве аргументов декораторам. Здесь слишком много кода для вставки, поэтому ознакомьтесь с реализацией этой функции.
Ответ 11
Я считаю, что имена переменных не хранятся в файлах pyc/pyd/pyo, поэтому вы не можете получить точные строки кода, если у вас нет исходных файлов.
Ответ 12
Если вы используете IPython, другой вариант заключается в использовании ??
после имени функции, чтобы увидеть ее исходный код. Вот пример:
[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
Ответ 13
Поскольку этот пост помечен как дубликат этого другого поста, я отвечу здесь за случай "лямбда", хотя ОП не касается лямбд.
Таким образом, для лямбда-функций, которые не определены в своих собственных строках: в дополнение к ответу marko.ristin, вы можете использовать мини-лямбду или SymPy, как предложено в этом ответе.
-
mini-lambda
легче и поддерживает любые операции, но работает только для одной переменной -
SymPy
тяжелее, но гораздо больше оснащена математическими/вычислительными операциями. В частности, это может упростить ваши выражения. Он также поддерживает несколько переменных в одном выражении.
Вот как вы можете сделать это с помощью 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))
Это правильно дает
def foo(arg1, arg2):
# do something with args
a = arg1 + arg2
return a
x ** 2
См. mini-lambda
документацию для деталей. Я, кстати, автор;)