dir関数とgetattr関数を組み合わせてオブジェクトの属性とその値を取得する方法やinspectモジュールが提供する関数を使って同様なことをさらに詳細に行う方法を紹介する。
o = 10
members = dir(o) # oの属性を取得
for m in members:
print(f'{m}: {getattr(o, m)}') # 属性とその情報を表示
members = [(member, getattr(o, member)) for member in dir(o)]
members.sort() # 属性名でソート
# inspectモジュールを使って同じことをする
import inspect
members = inspect.getmembers(o) # oの属性を取得
for name, value in members:
print(f'{name}: {value}')
members_ = inspect.getmembers(o)
members_.sort() # 属性名でソート
print(members == members_) # True
# inspectモジュールには「is」で始まる述語が用意されている
# ユーザー定義クラスのメソッドを取得する
class Foo:
def __init__(self):
pass
def bar(self):
pass
f = Foo()
print(inspect.ismethod(f.bar)) # True
methods = inspect.getmembers(f, inspect.ismethod)
print(methods)
# 出力結果:
# [('__init__', <bound method Foo.__init__ of <__main__.Foo object at
# 0x11e56be60>>), ('bar', <bound method Foo.bar of <__main__.Foo object at
# 0x11e56be60>>)]
methods = inspect.getmembers(Foo, inspect.ismethod)
print(methods) # []:インスタンスメソッドは取得できない
methods = inspect.getmembers(Foo, inspect.isfunction)
print(methods)
# 出力結果:
# [('__init__', <function Foo.__init__ at 0x10ef00220>),
# ('bar', <function Foo.bar at 0x10ef000e0>)]
o = 10.0
# inspect.ismethod関数はユーザー定義クラスのインスタンスメソッドかどうかを判定する
methods = inspect.getmembers(o, inspect.ismethod)
print(methods) # []
print(inspect.ismethod(o.is_integer)) # False
# inspect.isfunction関数はユーザー定義関数かどうかを判定する
methods = inspect.getmembers(o, inspect.isfunction)
print(methods) # []
# inspect.isbuiltin関数は組み込み関数または束縛された組み込みメソッドかどうかを判定する
methods = inspect.getmembers(o, inspect.isbuiltin)
print(methods) #
# inspect.isroutine関数は組み込み関数やユーザー定義関数、メソッドかどうかを判定する
methods = inspect.getmembers(o, inspect.isroutine)
print(methods) #
dir関数にオブジェクトを渡すと、そのオブジェクトの属性名(メンバ名)を要素とするリストが返される。これを使って以下のようなコードを書くと、属性名とその情報を得られる(属性がメソッドなどの呼び出し可能なものであればその情報が、値であればその値が表示される)。
例えば、以下は変数oに整数値10を代入し、int型のオブジェクトが持つ属性とその情報を表示している。
o = 10
members = dir(o) # oの属性を取得
for m in members:
print(f'{m}: {getattr(o, m)}') # 属性とその情報を表示
これを実行すると次のような結果が得られる。
また、リスト内包表記を使って属性一覧のリストも作成できる(作成したリストをソートしているのは後で比較を行うため)。
members = [(member, getattr(o, member)) for member in dir(o)]
members.sort() # 属性名でソート
dir関数でも属性の一覧を得られるが、inspectモジュールを使う方法もある。
inspectモジュールはオブジェクトから何らかの情報を取得するさまざまな関数を提供している。その一つとしてinspect.getmembers関数がある。この関数にオブジェクトを渡すと、(属性名, 値)というタプルを要素とするリストが返される。
以下に例を示す。
import inspect
members = inspect.getmembers(o) # oの属性を取得
for name, value in members:
print(f'{name}: {value}')
これは先ほどと同様に属性名とその値を表示するコードだ。実行結果は次のようになる。
dir関数を使った場合と同様な情報が得られていることが分かる。inspect.getmembers関数を使って得た属性一覧をソートしたものと、先ほどdir関数を使って作成した属性一覧をソートしたものを比較するとTrueとなることからも、これが分かる。
members_ = inspect.getmembers(o)
members_.sort() # 属性名でソート
print(members == members_) # True
一方、inspectモジュールには「is」で始まる関数が幾つか用意されている。例えば次のようなものだ。
inspect.getmembers関数にオブジェクトと上記の関数を渡すと、取得する属性を細かく制御できる。
例えば、以下のようなユーザー定義クラスを作成したとする。
class Foo:
def __init__(self):
pass
def bar(self):
pass
このクラスのインスタンスを生成して、barメソッドがメソッドかどうかを調べてみよう。
f = Foo()
print(inspect.ismethod(f.bar)) # True
この例ではinspect.ismethod関数にf.barメソッドを渡している。f.barはインスタンスメソッドなのでTrueが返された。このことを利用して、次のようなコードを書くと、ユーザー定義クラスのインスタンスメソッドの一覧を取得できる。
methods = inspect.getmembers(f, inspect.ismethod)
print(methods)
# 出力結果:
# [('__init__', <bound method Foo.__init__ of <__main__.Foo object at
# 0x11e56be60>>), ('bar', <bound method Foo.bar of <__main__.Foo object at
# 0x11e56be60>>)]
このように__init__メソッドとbarメソッドが得られた(出力結果にあるアドレスは環境によって異なることには注意されたい)。
これはFooクラスのオブジェクトfをinspect.getmembers関数に渡したので、このような結果になった。つまり、クラス自体をinspect.getmembers関数に渡すと、異なる結果が返ってくる。以下に例を示す。
methods = inspect.getmembers(Foo, inspect.ismethod)
print(methods) # []:インスタンスメソッドは取得できない
クラスオブジェクトという観点からはbarメソッドは(第0引数にインスタンスを指定する)関数のように見える。そのため、inspect.getmembers関数に述語としてinspect.isfunction関数を指定すると、メソッド一覧が得られる。
methods = inspect.getmembers(Foo, inspect.isfunction)
print(methods)
# 出力結果:
# [('__init__', <function Foo.__init__ at 0x10ef00220>),
# ('bar', <function Foo.bar at 0x10ef000e0>)]
inspect.getmembers関数で述語を指定するときには、どの関数を指定すると、どんな属性が得られるかを事前に把握しておく必要があるということだ。
今度は変数oに浮動小数点数値を代入し、以下のコードを試してみよう。
o = 10.0
methods = inspect.getmembers(o, inspect.ismethod)
print(methods) # []
inspect.ismethod関数を指定しているので、is_integerメソッドなどが一覧として取得できそうだが、そうはなっていない。これは上でも述べたように、inspect.ismethod関数は、与えられたオブジェクトがユーザー定義クラスのインスタンスメソッドかどうかを判定するものだからだ。floatクラスはユーザー定義クラスではないので、inspect.ismethod関数にo.is_integerメソッドを渡しても返されるのはFalseである。
print(inspect.ismethod(o.is_integer)) # False
同様に、inspect.isfunction関数はユーザー定義関数かどうかを判定するので、次のコードでもリストは空になる。
methods = inspect.getmembers(o, inspect.isfunction)
print(methods) # []
組み込み関数や束縛された組み込みメソッドかどうかを調べるにはinspect.isbuiltin関数を使用する。
methods = inspect.getmembers(o, inspect.isbuiltin)
print(methods) # 結果は以下の画像を参照
このコードを実行すると、float型のメソッド一覧が得られる。
inspect.isroutine関数はより広範にユーザー定義関数や組み込み関数、もしくはメソッドにマッチする。
methods = inspect.getmembers(o, inspect.isroutine)
print(methods) # 出力結果は省略
幅広く呼び出し可能なメソッド一覧を得たいのであればinspect.isroutine関数を、組み込みクラスのメソッドを得たいのであれば、inspect.isbuiltin関数を、ユーザー定義関数(のように見えるもの)を得たいのであればinspect.isfunction関数を、ユーザー定義クラスのインスタンスメソッドを得たいのであればinspect.ismethod関数を指定するようにしよう。
Copyright© Digital Advantage Corp. All Rights Reserved.