Pythonを勉強していると、「この型のメソッドは何だろう?」と思う時があります。
この時、オブジェクトを obj とすると
dir(obj)
とすることで、一覧を得ることができます。
たとえば、リスト型のメソッドを知りたいとします。dir() を使うと以下のようになります。
x = [1, 2] dir(x) [code lang=text] ['__add__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] [/code]
ここで、”–” からはじまるメソッドは特殊メソッドと言われ、その型の振る舞いを細かく調整するものとのことです。今回はここには踏み込みません。
今、私は、「通常メソッドだけリストアップしたい」と思いました。どうしたらできるでしょうか?
- short answer
以下の関数で求められます。
def get_normal_methods(obj): """ 指定されたオブジェクトの通常メソッドのリストを返す関数 :param obj: 通常メソッドを取得する対象のオブジェクト :return: 通常メソッドの名前のリスト """ normal_methods = [method for method in dir(obj) if not method.startswith('__')] return normal_methods def print_normal_methods(obj): """ 指定されたオブジェクトの通常メソッドの数と一覧を出力する関数 :param obj: 通常メソッドを出力する対象のオブジェクト """ typename = type(obj) normal_methods = get_normal_methods(obj) num_normal_methods = len(normal_methods) print(f'{typename} has {num_normal_methods} methods:') for method in normal_methods: print(method)
- long answer
- dir(x)の型とその要素の型
上記の関数に至った考え方を書いておきます。先程の例の通り、x は [1, 2] というリストが入っているとします。
dir(x) はlist型です。そして、リストの中を見ると、 `[‘__add__’, ‘__class__’, …]` となっていますので、リストの要素のひとつひとつはstr型のようです。
試しに、リストの最初の要素の型を見てみます
type(dir(x)[0]) <class 'str'>
予想どおり、str型でした。
今回、特殊メソッドは必ず “__” から始まるというルールがあります。なので、str型に「ある文字列から始まる」というメソッドがあるかどうかを調べてみたら、’startswith’ というメソッドがありました。
早速試してみます。
a = '__add__' a.startswith('__') True
“__” から始まっているので、Trueとなりました。これで、判定できそうです。
dir(x) はリストでした。なので、このリストを for を使って、ひとつひとつ変数 method に入れ、もし、”__” から始まっていなければ、normal_methods というリストに入れることにします。
リストの要素である method は str型のはずですので、ここで先程の startswith() メソッドを使うことにします。
normal_methods = [] for method in dir(x): if not method.startswith('__'): normal_methods.append(method) normal_method ['append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
お、通常メソッドだけリストで取り出すことに成功しました。
リストで for と if があると「リスト内包表記」にトライしようと思いました。
リスト内包表記は、いろいろやってみて、以下のように理解しました。
- リスト内包表記は、リストを作成するための表記である
- 一番最初に来る変数は、リスト内の変数
- forを組み合わせることで、append を使わずにリストの中に追加されていくイメージ
- ifを使う時は、forの後にそのまま書く
つまり、
[ リストに追加する変数 for 変数 in リストなど if 条件式 ]
となるわけです。
今、上記の for と if 文を日本語にすると、
- dir(x) の要素を ひとつ 変数method に投入
- method に入った文字列が、’__’ から始まらなければ、method を そのままリストに追加
としています。なので、追加されるものは method だということになります。
ということで、
normal_methods = [method for method in dir(x) if not method.startswith('__')
と書けると理解できました。
その型がいくつの通常メソッドを持っているか知りたいと思いました。これは、リストの要素を数えればいいので、len()関数を使えば大丈夫です。
len(normal_methods) 11
これは、リストをひとつずつ改行して表示すればいいと思いました。
for method in normal_methods: print(method) append clear copy count extend index insert pop remove reverse sort
列挙できました。
そうしたらこれらを関数にまとめればおしまいです。通常メソッドを取得する関数と、それを表示する関数の2つに分けることで汎用性が高まると考えました。
取得する関数を get_normal_methods(オブジェクト)
表示する関数を print_normal_methods(オブジェクト)
とします。
def get_normal_methods(obj): normal_methods = [method for method in dir(obj) if not method.startswith('__')] return normal_methods def print_normal_methods(obj): typename = type(obj) normal_methods = get_normal_methods(obj) num_normal_methods = len(normal_methods) print(f'{typename} has {num_normal_methods} methods:') for method in normal_methods: print(method)
これで無事にできました。
実際やってみます。
print_normal_methods([1, 2]) <class 'list'> has 11 methods: append clear copy count extend index insert pop remove reverse sort
[1, 2] というオブジェクトは list型であり、11個のメソッドがあるということがわかりました。
これでメソッドの一覧をすぐに作れるようになりました。リスト内包表記の最初の変数は、appendで示す内容だという気付きも大きかったです。