以下に定義するPython関数があるとします。
def foo(arg1,arg2):
#do something with args
a = arg1 + arg2
return a
関数の名前はを使用して取得できますfoo.func_name
。上記で入力したように、プログラムでソースコードを取得するにはどうすればよいですか?
foo.__name__
以下に定義するPython関数があるとします。
def foo(arg1,arg2):
#do something with args
a = arg1 + arg2
return a
関数の名前はを使用して取得できますfoo.func_name
。上記で入力したように、プログラムでソースコードを取得するにはどうすればよいですか?
foo.__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
しかし、関数が文字列、ストリーム、またはコンパイル済みファイルからインポートされた場合、そのソースコードを取得できないと思います。
len
。len
関数のソースコードはどこにありますか?
inspect.getsourcelines(foo)
モジュールは、検査 Pythonオブジェクトからソースコードを取得するためのメソッドを有します。ソースがファイルにある場合にのみ機能するようです。それがあれば、オブジェクトからソースを取得する必要はないと思います。
python 3.5.3
インタプリタでinspectを使ってみました。import inspect
+ inspect.getsource(foo)
うまくいきました。
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
dir(MyClass)
し、MyClass.__init__??
というように。
これinspect
は良い答えだと私は概ね同意しますが、インタープリターで定義されたオブジェクトのソースコードを取得できないことには同意しません。dill.source.getsource
from を使用すると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
>>>
dill.source.getsource
関数、クラス、ラムダなどのインタープリターの履歴を検査します。execに渡される文字列の内容は検査しません。
dill
:この質問に答えるためにstackoverflow.com/questions/13827543/...
dill.source
ような関数がgetname
ありimportable
、getsource
特定のオブジェクトのソースコード(またはオブジェクトを生成するインポート可能ファイル)を取得することに焦点を当てています。ソースint
がないなどの単純なものの場合、ソースは期待どおりに機能しません(つまり、「a = 10」の場合は「10」を返します)。
>>> a = 10; print( [key for key, val in globals().items() if val is a][0] )
dill
が、私の答えは少し望まれます(つまり、同じ値に複数の名前がある場合、どちらが使用されたかを理解できません。式を渡すと、その式が何であったかを言うことはできません。名前と同じように評価される式を渡すと、代わりにその名前が与えられます。)dill
私の答えのこれらの欠点のいずれかを解決できますこちら:stackoverflow.com/a/28634996/901641
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
ます。ただし、ソースファイルからコードをインポートする場合はどちらでも問題ありません。
getsource(foo)
。
inspect
モジュールを使用して、その完全なソースコードを取得できます。モジュールgetsource()
からそのためのメソッドを使用する必要がありinspect
ます。例えば:
import inspect
def get_my_code():
x = "abcd"
return x
print(inspect.getsource(get_my_code))
以下のリンクで他のオプションを確認できます。 Pythonコードを取得する
この投稿はこの他の投稿の重複としてマークされているため、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
ドキュメントを参照してください。ちなみに私は作者です;)
受け入れられた回答は、ラムダが別の行に指定されている場合にのみ機能することに注意してください。関数への引数としてそれを渡し、ラムダのコードをオブジェクトとして取得したい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でそれを正確に行う必要がありました。ここに貼り付けるにはコードが多すぎるため、この関数の実装を確認してください。
関数を自分で厳密に定義していて、それが比較的短い定義である場合、依存関係のない解決策は、関数を文字列で定義し、式のeval()を関数に割り当てることです。
例えば
funcstring = 'lambda x: x> 5'
func = eval(funcstring)
次に、オプションで元のコードを関数に添付します。
func.source = funcstring