2014/10/27

Python Tips:オブジェクトのメソッドを調べたい

Pythonでオブジェクトのメソッドを調べる方法をご紹介します。

大きく2つの方法があるかと思います。
  1. 組み込みの関数で調べる
  2. inspect ライブラリの関数で調べる

順に見ていきます。


組み込みの関数で調べる

こちらは特にライブラリを読み込まなくても使える方法です。

組み込みの dir getattr callable 関数を使います。こんな感じ。
# メソッドを調べたいオブジェクト
# 今回は適当に文字列を使う
obj = ""

# アトリビュート一覧のうち
# callable なオブジェクトのみを表示する
for attr in dir(obj):
    if callable(getattr(obj, str(attr))):
        print attr

メソッド一覧をリストで取得したい場合は次のようにするとよいでしょうか。
obj_methods = [attr for attr in dir(obj) if callable(getattr(obj,  str(attr)))]

ただし、 callable はメソッド以外のオブジェクトーーたとえば関数やクラスに対しても True を返すので、その点は注意が必要です。
print callable(list)  # => True
print callable(lambda x: x)  # => True

class MyClass:
    pass

print callable(MyClass)  # => True

純粋にメソッドだけを抽出したい場合は次の inspect を使うやり方でいくのがよろしいかと思います。


inspect ライブラリの関数で調べる

inspect ライブラリの関数を使う方法もあります。

こちらは inspect の getmembers 関数あたりを使います。たとえばこんな感じ。
# ライブラリの読み込み
import inspect

# 対象オブジェクト
obj = ""

# アトリビュート一覧のうち
# isbuiltin が True を返すオブジェクトのみを表示する
# さらに末尾の5件のみに絞り込み
print inspect.getmembers(obj, inspect.isbuiltin)[-5:]
# => [('swapcase', ), ...]
この場合、組み込みのメソッドか関数のみが表示されます。

getmembers 関数は、オブジェクトのアトリビュート一覧を名前と中身をペアにして返す関数です。 第2引数に関数を渡すとその戻り値が True となるものだけにフィルタしてくれます。

isbuiltin 関数は組み込みの関数やメソッドに対して True を返すものです。

isbuiltin を ismethod などに変えると、自作のメソッドのみに絞り込むことも可能です。
print inspect.getmembers(obj, inspect.ismethod)
# => obj の自作メソッド一覧

inspect には他にも細かく判定する関数がいくつも用意されているので、適切な関数を選んで使われるとよろしいかと思います。


以上です。


参考
How do you get list of methods in a python class? - Stack Overflow
python - Finding what methods an object has - Stack Overflow
27.13. inspect — Inspect live objects — Python公式ドキュメント

2014/10/21

Python Tips:リストを指定した数の要素ごとにまとめたい

Pythonで、リストの要素を指定した数でグルーピングして返す方法をご紹介します。

最もシンプルなやり方は range でステップを指定しながらループを回してスライスする方法かと思います。
# 0, 1, 2, ... 14 のリストを作成
li = list(range(15))

# 要素を3つずつ順番にグループ化
group_by = 3
[li[i:i + group_by] for i in range(0, len(li), group_by)]
# => [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12, 13, 14]]
# 3 つずつに区切られたリストが返される

その他の方法としては、 iter 関数と zip 関数、スプラット演算子などを組み合わせて合わせ技で作る方法なんかもあります。
# 0, 1, 2, ... 14 のリストを作成
li = list(range(15))

group_by = 3
chunks = zip(*[iter(li)]*group_by)
print chunks
# => [(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, 14)]
ただ、この場合はなぜこうなるのか一目ではわからない感じです。。ほんの数文字の間にいろんな処理が挟まっていてテクニックとしては面白いのですが、、あくまでもトリック的な感じですかね。。

以上です。


参考
How do you split a list into evenly sized chunks in Python? - Stack Overflow
2. Built-in Functions — Python公式ドキュメント

2014/10/14

Python Tips:Python2 で Python3 の print 関数を使いたい

Python2でPython3の print 関数を使う方法をご紹介します。

__future__ ライブラリから print_function をインポートすることで、Python3のものと同等の print 関数が使えるようになります。
from __future__ import print_function

Python3の print 関数であれば、Python2の print 文にはなかったさまざまなオプションが使えるようになります。

たとえば、複数の引数を print 関数に渡したときの区切り文字を指定するには、 sep オプションを使います。
print("Red", "Hot", "Chili", sep="\n")
# => 改行つきで Red Hot Chili が順に表示される

末尾の改行コードをコントロールしたい場合には end オプションを使います。
from __future__ import print_function

print("Red", "Hot", "Chili", end="")  # => Red Hot Chili
# 末尾に改行コードが追加されない
これはPython2 で print value, と最後に , をつけるのと近い感じですね。

出力先を標準出力ではなくファイルに変えたい場合は、 file オプションにファイルオブジェクトを渡します。
f = open("test.txt", "w")

print("Red", "Hot", "Chili", file=f)

f.close()
# test.txt ファイル内に Red Hot Chili と書き込まれる


以上です。

使いどころは多くはなさそうですが、、万が一Python2のコードの中でPython3スタイルの print 関数を使う必要が出てきたときには、いいかもしれません


参考
PEP 3105 print as a function - What’s New in Python 2.6

2014/10/07

ライブラリ:re

Pythonの「 re 」というライブラリをご紹介します。

import re

re は正規表現を扱うためのライブラリです。 re = Regular Expression の略ですね。

re の基本的な使い方を以下、見ていきます。


re.search

re.search は探索のための関数です。与えられたテキストの中の正規表現パターンを探索します。

例えばこんな感じ。
# ライブラリ読み込み
import re

# 対象テキスト
text = """
When you were born,
you cried and the world rejoiced.
Live your life so that when you die,
the world cries and you rejoice.
"""

# 一致するパターンを検索
# 「d」で終わる単語を探す
result = re.search(r"\w+d", text)

# 見つかれば結果を表示
# 見つからなければ no match とだけ表示
if result:
    print result.group()  # => 最初に一致したパターン
    print result.start(), result.end()  # => 一致した箇所のインデックス
    print result.span()  # => 上の start と end のタプル
else:
    print "no match"

re.search が返す値は、一致するパターンが
見つかった場合 マッチオブジェクト
見つからなかった場合 None
となりますので、上の例のように search の戻り値を if で判定することによって見つかった場合と見つからなかった場合の処理を分けることができます。


re.findall

re.findall も探索のための関数です。
re.search が一致したパターンをひとつだけ返すのに対し、 re.findall はすべての一致パターンを返します。

こちらも例を。
results = re.findall(r"\w+d", text)

# 見つかれば結果を表示
# 見つからなければ no match とだけ表示
if results:
    # 一致したパターンを空白区切りですべて表示
    for r in results:
        print r,
        print ""
    else:
        print "no match"

findall は結果をすぐさまリストにしますが、同様の処理をして結果をイテレータとして返すものとして finditer という関数もあります。


re.split

re.split は分割のための関数です。指定した正規表現パターンを区切り文字にしてテキストを分割します。結果はリストで返ってきます。

こんな感じです。
sentences = re.split(r"\W", text)

print sentences
# => text をアルファベットと数字以外のすべての文字を区切り文字にして分割したリスト


re.sub

re.sub は置換のための関数です。正規表現パターンと一致する部分を別の文字列に置換した文字列を返します。

こんな感じです。
text_replaced = re.sub(r"\w+d", "***", text)

print text_replaced  # => d で終わる単語がすべて *** に置換された文字列

デフォルトでは、一致したパターンがすべて置換されて返ってきます。

置換する最大数を指定したい場合はキーワード引数 count を使います。
text_replaced = re.sub(r"\w+d", "***", text, count=3)

こうすると、 count に指定した数値を上限回数として置換してくれます。


以上です。

今回はこの4つの関数を見てみました。
  • re.search 検索 1つだけ
  • re.findall 検索 複数個 ジェネレータの re.finditer も存在する
  • re.split 分割
  • re.sub 置換

これらの他にも、関数 re.compile (正規表現パターンオブジェクトを生成できる関数)や正規表現オプションなど、正規表現がらみの便利な機能が豊富に用意されています。

詳しく知りたい場合は、参考ページを参照してみてください。


参考
Python Regular Expressions - Educational Materials — Google Developers
Regular Expressions in Python. Python Tutorials.
Regular Expression HOWTO — Python公式ドキュメント

Pythonでの正規表現の簡単なまとめ - minus9dの日記
正規表現 (Regular Expression) - Python 入門

追記20141009
参考リンクの Google Developers のページを日本語訳されている方がいるということでコメントをいただきました。こちらもよろしければ。
Python の正規表現 - 手習い録