以下に定義するようなPython関数があるとします。
def foo(arg1,arg2):
#do something with args
a = arg1 + arg2
return a
foo.func_name
を使って関数の名前を取得できます。上記で入力したように、プログラムでそのソースコードを取得する方法を教えてください。
関数がファイルシステムで利用可能なソースファイルからのものである場合、 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
しかし、関数が文字列、ストリーム、またはコンパイル済みファイルからインポートされたものである場合、そのソースコードを取得することはできません。
inspectモジュール はpythonオブジェクトからソースコードを取得するためのメソッドを持っています。一見、ソースがファイル内にある場合にのみ機能します。あなたがそれを持っていたら私はあなたがオブジェクトからソースを取得する必要はないだろうと思います。
ソースコードが利用できない場合、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
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
私は一般的にinspect
が良い答えであることに同意しますが、私はあなたがインタプリタで定義されたオブジェクトのソースコードを手に入れることができないことに反対します。 dill
からdill.source.getsource
を使用すると、対話的に定義されていても、関数とラムダのソースを取得できます。それはまたカレーで定義された束縛されたあるいは束縛されていないクラスメソッドや関数からのコードを取得することができます。
>>> 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
>>>
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
は使用しません。ただし、ソースファイルからコードをインポートする場合は、どちらでも問題ありません。
そのための完全なソースコードを取得するためにinspect
モジュールを使うことができます。そのためにはinspect
モジュールからgetsource()
メソッドを使用する必要があります。例えば:
import inspect
def get_my_code():
x = "abcd"
return x
print(inspect.getsource(get_my_code))
あなたはそれを下のリンクでより多くのオプションをチェックアウトすることができます。 あなたのPythonコードを取得してください
要約する :
import inspect
print( "".join(inspect.getsourcelines(foo)[0]))
あなた自身が厳密に関数を定義していて、それが比較的短い定義であるならば、依存性のない解決策は文字列で関数を定義して、そしてあなたの関数に式のeval()を割り当てることでしょう。
例えば。
funcstring = 'lambda x: x> 5'
func = eval(funcstring)
次に、オプションで元のコードを関数に添付します。
func.source = funcstring
受け入れられた答えはラムダが別の行に与えられている場合にのみ機能することに注意してください。関数の引数として渡して、ラムダのコードをオブジェクトとして取得したい場合は、inspect
で行全体が表示されるため、問題は少し複雑になります。
たとえば、ファイルtest.py
を考えます。
import inspect
def main():
x, f = 3, lambda a: a + 1
print(inspect.getsource(f))
if __== "__main__":
main()
それを実行することはあなたに与えます(意図を気にしてください!):
x, f = 3, lambda a: a + 1
ラムダのソースコードを取得するには、(f.__code__.co_filename
を使用して)ソースファイル全体を再解析し、行番号とそのコンテキストでlambda ASTノードを一致させるのが最善の策です。
コントラクトによるデザインライブラリ icontract では、デコレータに引数として渡したラムダ関数を解析する必要があるため、これを正確に行う必要がありました。ここに貼り付けるにはコードが多すぎるので、 この関数の実装 をご覧ください。
この記事は この他の記事 の複製としてマークされているので、OPはラムダについてではありませんが、ここでは "ラムダ"の場合について答えます。
そのため、独自の行に定義されていないラムダ関数に対しては、 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
documentation をご覧ください。ところで私は作者です;)
I 信じる変数名はpyc/pyd/pyoファイルに保存されないので、ソースファイルがなければ正確なコード行を取得することはできません。
IPythonを使用している場合、もう1つの選択肢は、関数名の後に??
を使用してそのソースコードを確認することです。これが一例です。
[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