파이썬 함수의 소스 코드를 어떻게 얻을 수 있습니까?


406

아래에 정의 된 Python 함수가 있다고 가정하십시오.

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

를 사용하여 함수의 이름을 얻을 수 있습니다 foo.func_name. 위에서 입력 한대로 프로그래밍 방식으로 소스 코드를 얻는 방법은 무엇입니까?



1
파이썬 3에서는 다음을 사용하여 함수 이름을 얻을 수 있습니다.foo.__name__
MikeyE

다른 것들도 많이 얻을 수 있습니다 .
not2qubit

답변:


541

함수가 파일 시스템에서 사용 가능한 소스 파일에서 온 것이라면 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
튜플을 반환 합니다. tuple [0]은 소스 코드의 행을 나타내는 문자열 목록이고 tuple [1]은 실행 컨텍스트에서 행 번호입니다. IPython에서; 이것은 전체 노트북이 아닌 내의 줄 번호입니다.
The Red Pea

12
이 답변은 명시 적으로 언급하지 않지만 inspect.getsource (foo)는 tuple [0]이 행 목록 인 튜플 대신 단일 문자열로 소스를 반환합니다. getsource는 repl을 들여다 볼 필요가 있다면 더 유용 할 것입니다
whaley

예를 들어 function과는 작동하지 않습니다 len. len함수 의 소스 코드는 어디에서 찾을 수 있습니까 ?
oaklander114

1
또는inspect.getsourcelines(foo)
Sławomir Lenart

1
@ oaklander113 inspect.getsource는 표준 라이브러리의 대부분의 함수와 같은 내장 기능과 작동하지 않습니다. 웹 사이트 또는 Github
Nicolas Abril

183

모듈 검사 파이썬 객체의 소스 코드를 검색하는 방법이있다. 소스가 파일에있는 경우에만 작동합니다. 당신이 가지고 있다면 객체에서 소스를 얻을 필요가 없다고 생각합니다.


3
예, 파일에 정의 된 객체에 대해서만 작동하는 것 같습니다. 통역사에 정의 된 사람들에게는 해당되지 않습니다.
sastanin

3
놀랍게도, 그것은 Ipython / Jupyter 노트북에서도 작동합니다
Dr. Goulu

1
python 3.5.3통역사 에서 inspect를 사용해 보았습니다 . import inspect+ inspect.getsource(foo)잘 작동했습니다.
André C. Andersen

@ AndréChristofferAndersen 네,하지만 인터프리터에 정의 된 함수에는 작동하지 않습니다
누군가

86

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

1
내장에 대한 TypeError를 발생시킵니다.
누 메논

8
그들은 파이썬에서 일반적으로 어떤 소스 코드가 없기 때문에 @Noumenon, 그들은 C로 작성
schlamar

83

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

9
실수로 작성하고 테스트 한 하루를 보냈던 기능이 포함 된 하나 이상의 셀을 실수로 삭제 한 경우 IPython 및 Jupyter 노트북에서 매우 유용합니다.
AGS

전체 클래스를 잃은 누구에게 : 당신은 방법으로 그것을 방법을 복원 할 수 있습니다 dir(MyClass), 다음 MyClass.__init__??등등.
Valerij

61

나는 그것이 inspect좋은 대답 이라고 일반적으로 동의하지만 통역사에 정의 된 객체의 소스 코드를 얻을 수 없다는 것에 동의하지 않습니다. dill.source.getsourcefrom 을 사용 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

>>> 

1
@ Ant6n : 글쎄, 그것은 비열한 것입니다. dill.source.getsource함수, 클래스, 람다 등의 인터프리터 히스토리를 검사합니다. exec에 전달 된 문자열의 내용은 검사하지 않습니다.
Mike McKerns

이것은 매우 흥미로운 것 같습니다. dill이 질문에 대답하는 데 사용할 수 있습니까 : stackoverflow.com/questions/13827543/…
ArtOfWarfare

@ArtOfWarfare : 부분적으로 그렇습니다. 주어진 객체에 대한 소스 코드 (또는 객체를 생성하는 가져 오기 가능)를 얻는 데 중점을 둔 and 및 그 dill.source기능을 가지고 있습니다 . 소스 가 없는 간단한 것들의 경우 예상대로 작동하지 않습니다 (예 : 'a = 10'의 경우 '10'을 반환합니다). getnameimportablegetsourceint
Mike McKerns

그러나 이것은 전 세계에 적용됩니다 : >>> a = 10; print( [key for key, val in globals().items() if val is a][0] )
Mike McKerns

@ MikeMKKerns :을 사용하지 않고 그 질문에 대답하기 위해 최선을 다 dill했지만 내 대답은 약간의 희망을 남깁니다. 이름과 같은 이름으로 평가되는 표현식을 전달하면 대신 해당 이름을 부여합니다.) dill내 대답의 단점을 해결할 수 있습니다. 여기 : stackoverflow.com/a/28634996/901641
ArtOfWarfare

21

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

편집 : @ 0sh에서 지적한 것처럼이 예제는 ipython평범하지는 않지만 작동합니다 python. 그러나 소스 파일에서 코드를 가져올 때는 두 가지 모두에 적합합니다.


2
인터프리터가 foo를 바이트 코드로 컴파일하고 소스 코드를 버리고 실행하려고하면 OSError가 발생하므로 작동하지 않습니다 getsource(foo).
Milo Wielondek

바닐라 파이썬 인터프리터에 관한 한 @ 0sh 좋은 지적. 그러나 IPython을 사용할 때 위의 코드 예제가 작동합니다.
TomDotTom

11

inspect모듈을 사용 하여 전체 소스 코드를 얻을 수 있습니다 . 모듈 getsource()에서 그 방법 을 사용해야 inspect합니다. 예를 들면 다음과 같습니다.

import inspect

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

print(inspect.getsource(get_my_code))

아래 링크에서 더 많은 옵션을 확인할 수 있습니다. 파이썬 코드를 검색


7

이 게시물은 이 다른 게시물 의 복제본으로 표시되어 있기 때문에 OP는 람다가 아니지만 "lambda"사례에 대해 여기에 대답합니다.

따라서 자체 줄에 정의되어 있지 않은 람다 함수의 경우 : marko.ristin 의 답변 외에도 mini-lambda를 사용 하거나이 답변 에서 제안 된 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 설명서 를 참조하십시오. 그건 그렇고 저자입니다;)


5

람다가 별도의 줄에 주어진 경우에만 허용되는 답변이 작동합니다. 함수에 인수로 전달하고 람다의 코드를 객체로 검색하려면 문제가 조금 까다로워 inspect전체 줄을 제공합니다.

예를 들어 파일을 고려하십시오 test.py.

import inspect

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

if __name__ == "__main__":
    main()

그것을 실행하면 (indention을 명심하십시오!)

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

람다의 소스 코드를 검색하려면 가장 좋은 방법은 전체 소스 파일을 다시 구문 분석하고 (을 사용하여 f.__code__.co_filename) 람다 AST 노드를 줄 번호와 컨텍스트로 일치시키는 것입니다.

우리는 설계자 별 라이브러리 icontract 에서 우리가 데코레이터에게 인수로 전달하는 람다 함수를 구문 분석해야 했기 때문에 정확하게 수행 해야했습니다. 여기에 붙여 넣기에는 너무 많은 코드가 있으므로이 함수의 구현을 살펴보십시오 .


4

함수를 직접 정의하고 비교적 짧은 정의 인 경우 종속성이없는 해결책은 문자열에서 함수를 정의하고 표현식의 eval ()을 함수에 할당하는 것입니다.

예 :

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

그런 다음 선택적으로 원래 코드를 함수에 첨부하십시오.

func.source = funcstring

2
eval ()을 사용하면 일종의 대화 형 Python 인터프리터를 작성하지 않는 한 정말 나쁜 것 같습니다. 평가는 심각한 보안 문제를 일으 킵니다. 평가 문자열 리터럴 만 사용하는 정책을 채택하면 구문 강조에서 평가 멤버를 포함하는 클래스의 적절한 반영에 이르기까지 다양한 유용한 동작을 잃게됩니다.
Mark E. Haase

2
공감. @ mehaase : 보안은 분명히 문제가되지 않습니다. 구문 강조 표시가 부족하다는 것은 IDE의 결함과 파이썬이 동종 언어가 아니라는 사실의 조합이라고 말하지만 다른 의견은 상당히 관련이 있습니다.
ninjagecko

7
@ninjagecko 보안은 일반 대중에게 조언을 제공 할 때 항상 문제입니다. 대부분의 독자는 인터넷 검색 질문 때문에 여기에옵니다. 많은 사람들이이 답변을 그대로 복사 할 것이라고 생각하지 않습니다. 대신, 그들은 배운 개념을 자신의 문제에 적용 할 것입니다.
Mark E. Haase


0

내가 생각 당신이 소스 파일이없는 경우 정확한 코드 라인을 검색 할 수 있도록 변수 이름, PYC / PYD / 이영표 파일에 저장되지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.