オブジェクトの情報を探る(3) - ソースコードの情報
【 目次 】
cleandoc関数 - ドキュメンテーション文字列をクリーンアップ。
cleandoc関数を使うとオブジェクトのドキュメンテーション文字列をクリーンアップした文字列に変換できる。
公式ドキュメントには
インデントされた docstring から、コードブロックまでのインデントを削除します。 2行目以降では行頭の空白は一様に削除されます。全てのタブはスペースに展開されます。
文字列からインデントを削除する例
import inspect doc_string=" MyClsクラスはサンプルクラスです" print inspect.cleandoc(doc_string)
実行結果
MyClsクラスはサンプルクラスです
関数のドキュメンテーション文字列とそのクリーンアップ後の文字列を表示してみる。
import inspect def avg_func(*args): u""" 複数の引数の値の平均値を求めます :arg_list 処理対象の数値のリスト :returns 平均値 """ total=0 for num in args: total+=num return total/len(args) print " === クリーンアップ前のドキュメンテーション文字列 ===" print avg_func.__doc__ print " === クリーンアップ後のドキュメンテーション文字列 ===" print inspect.cleandoc(avg_func.__doc__)
実行結果
=== クリーンアップ前のドキュメンテーション文字列 === 複数の引数の値の平均値を求めます :arg_list 処理対象の数値のリスト :returns 平均値 === クリーンアップ後のドキュメンテーション文字列 === 複数の引数の値の平均値を求めます :arg_list 処理対象の数値のリスト :returns 平均値
getdoc関数 - オブジェクトのドキュメンテーション文字列を取得
getdoc関数により、オブジェクトのクリーンアップされたドキュメンテーション文字列を取得する事ができる。
import inspect class MyCls(object): "MyClsクラスはサンプルクラスです" print u"=== MyClsクラスのドキュメンテーション文字列 ===" print inspect.getdoc(MyCls) print print u"=== inspectモジュールのドキュメンテーション文字列 ===" print inspect.getdoc(inspect)
実行結果
=== MyClsクラスのドキュメンテーション文字列 === MyClsクラスはサンプルクラスです === inspectモジュールのドキュメンテーション文字列 === Get useful information from live Python objects. This module encapsulates the interface provided by the internal special attributes (func_*, co_*, im_*, tb_*, etc.) in a friendlier fashion. It also provides some help for examining source code and class layout. Here are some of the useful functions provided by this module: ismodule(), isclass(), ismethod(), isfunction(), isgeneratorfunction(), isgenerator(), istraceback(), isframe(), iscode(), isbuiltin(), isroutine() - check object types getmembers() - get members of an object that satisfy a given condition getfile(), getsourcefile(), getsource() - find an object's source code getdoc(), getcomments() - get documentation on an object getmodule() - determine the module that an object came from getclasstree() - arrange classes so as to represent their hierarchy getargspec(), getargvalues(), getcallargs() - get info about function arguments formatargspec(), formatargvalues() - format an argument spec getouterframes(), getinnerframes() - get info about frames currentframe() - get the current stack frame stack(), trace() - get info about frames on the stack or in a traceback
getcomments関数 - オブジェクトのコメント行を取得
getcomments関数により、クラス,関数,メソッド,モジュールの先頭にあるコメント行 (複数行) を、単一の文字列として取得する事ができる。
# coding: UTF-8 import inspect # MyClsクラス class MyCls(object): pass print u"=== MyClsクラスのコメント行 ===" print inspect.getcomments(MyCls) print print u"=== inspectモジュールのコメント行 ===" print inspect.getcomments(inspect)
実行結果
=== MyClsクラスのコメント行 === # MyClsクラス === inspectモジュールのコメント行 === # -*- coding: iso-8859-1 -*-
getfile関数 - オブジェクトを定義しているモジュールのファイル名を取得
getfile関数により、オブジェクトの定義されているモジュールのファイル名を取得する事ができる。
公式ドキュメントには
オブジェクトを定義している (テキストまたはバイナリの) ファイルの名前を返します。オブジェクトが組み込みモジュール、クラス、関数の場合は TypeError 例外が発生します。
「組み込みモジュール、クラス、関数の場合は TypeError 例外が発生します。」とある。
試しにクラス、関数のファイル名を取得してみる。
import inspect def func(): pass class MyCls(object): pass print inspect.getfile(func) print inspect.getfile(MyCls)
正常にソースファイルのファイル名が表示できる。
では、標準モジュール(標準ライブラリのモジュール)のオブジェクトの場合はどうだろう?
# 標準モジュールのモジュールオブジェクト print inspect.getfile(inspect), type(inspect) # 標準モジュールのクラスオブジェクト print inspect.getfile(inspect.ArgInfo), type(inspect.ArgInfo) # 標準モジュールの関数オブジェクト print inspect.getfile(inspect.getfile), type(inspect.getfile)
実行結果
pythonのインストールデレクトリ\lib\inspect.pyc <type 'module'> pythonのインストールデレクトリ\lib\inspect.pyc <type 'type'> pythonのインストールデレクトリ\lib\inspect.py <type 'function'>
これも問題ない。
しかし、ファイルの拡張子について注目してみると「py」であったり「pyc」であったりする。
関数の戻り値が、「コンパイルされたファイル」の場合もあるので注意。
でも、
import sys inspect.getfile(sys)
を実行すると、エラーが発生。
実行結果
TypeError: <module 'sys' (built-in)> is a built-in module
Python 標準ライブラリ — Python 2.7.x ドキュメント によると
Python プログラマが直接アクセスできないシステム機能へのアクセス機能を提供する (Cで書かれた) 組み込みモジュール
という文言が出てくる。
組み込みモジュールの意味は、
組込み関数や組込み型が定義されているモジュールなどのCで書かれた特別なモジュールなどを指すのだろう。
組込み関数lenや組込み型intで試してみると
print inspect.getfile(len)
実行結果
TypeError: <built-in function len> is not a module, class, method, function, traceback, frame, or code object
print inspect.getfile(int)
実行結果
raise TypeError('{!r} is a built-in class'.format(object)) TypeError: <module '__builtin__' (built-in)> is a built-in class
とTypeErrorが発生する。
では、変数xに対してはどうだろう?
x=10 print inspect.getfile(x)
や
x="abc" print inspect.getfile(x)
は
TypeErrorとなる。
しかし、
x = func
や
x = MyCls
とした場合は
print inspect.getfile(x)
でエラーは発生しない。
これはxに代入された値が前者の場合は組込みの型(のインスタンス)や関数であったためにエラーとなったが、後者の場合にはユーザ定義の(組込みでは無い)型や関数のためエラーにはならない。
さらに、ユーザ定義のインスタンスオブジェクトの場合はどうだろう?
x = MyCls() print inspect.getfile(x)
実行結果
TypeError: <__main__.MyCls object at 0x0000000002573780> is not a module, class, method, function, traceback, frame, or code object
インスタンスオブジェクトの場合は組込みであろうと無かろうとエラーが発生するようだ。
getsourcefile関数 - オブジェクトを定義しているモジュールのソースファイル名を取得
getsourcefile関数を使ってオブジェクトの定義されてているモジュールのソースファイル名を取得する事ができる。
getfile関数との違いはバイナリファイル(拡張子がpyc)では無く必ずソースファイル名が返される事。
import inspect print inspect.getfile(inspect.ArgInfo) print inspect.getsourcefile(inspect.ArgInfo)
実行結果
pythonのインストールデレクトリ\lib\inspect.pyc pythonのインストールデレクトリ\lib\inspect.py
公式ドキュメント によると
オブジェクトを定義している Python ソースファイルの名前を返します。オブジェクトが組み込みのモジュール、クラス、関数の場合には、 TypeError 例外が発生します。
これも、変数xが定義されているモジュールのソースファイル名を取得しようとして
class MyCls(object): pass x=MyCls inspect.getsourcefile(x)
は、xの値がユーザ定義のクラスオブジェクトであるので問題無いが
x=MyCls() inspect.getsourcefile(x)
とするとxの値がインスタンスオブジェクトであるため、エラーになってしまうので注意。
getsourcelines関数 - オブジェクトのソース行のリストと開始行番号を取得
公式ドキュメント によると
オブジェクトのソース行のリストと開始行番号を返します。引数にはモジュール、クラス、メソッド、関数、トレースバック、フレーム、コードオブジェクトを指定することができます。戻り値は指定したオブジェクトに対応するソースコードのソース行リストと元のソースファイル上での開始行となります。ソースコードを取得できない場合は IOError が発生します。
ユーザ定義クラスMyClsのソース行のリストと開始行番号を表示してみる。
# coding: UTF-8 import inspect class MyCls(object): def method(self): pass print inspect.getsourcelines(MyCls)
実行結果
(['class MyCls(object):\n', ' def method(self):\n', ' pass\n'], 5)
getsource関数 - オブジェクトのソースコードを取得
公式ドキュメント によると
オブジェクトのソースコードを返します。引数にはモジュール、クラス、メソッド、関数、トレースバック、フレーム、コードオブジェクトを指定することができます。ソースコードは単一の文字列で返します。ソースコードを取得できない場合は IOError が発生します。
inspectモジュールのgetsource関数自身のソースを表示させてみると
import inspect print inspect.getsource(inspect.getsource)
実行結果
def getsource(object): """Return the text of the source code for an object. The argument may be a module, class, method, function, traceback, frame, or code object. The source code is returned as a single string. An IOError is raised if the source code cannot be retrieved.""" lines, lnum = getsourcelines(object) return string.join(lines, '')
関数内部でgetsourcelines関数を呼んでいるのがわかる。