note.nkmk.me

Pythonのoperatorモジュールの使い方(itemgetterなど)

Posted: 2020-09-13 / Tags: Python

Pythonの標準ライブラリのoperatorモジュールでは、+<などの演算子に対応する関数や、オブジェクトの要素、属性を取得したりメソッドを実行したりする呼び出し可能オブジェクトを生成する関数が提供されている。

呼び出し可能オブジェクトを指定する引数にoperatorの関数を使うと、シンプルに書けたり、より高速に処理できたりする。

ここでは、以下の内容について説明する。

  • 組み込み演算子に対応する関数
    • 算術演算子
    • 比較演算子
    • 論理演算子
  • オブジェクトの要素を取得: operator.itemgetter()
  • オブジェクトの属性を取得: operator.attrgetter()
  • オブジェクトのメソッドを実行: operator.methodcaller()

公式ドキュメントに演算子とoperatorモジュールの関数の対応がまとめられている。本記事で扱っていないものもあるので、一覧は以下を確認されたい。

operator.itemgetter(), attrgetter(), methodcaller()sorted()関数などの引数keyに使われることが多い。具体例などの詳細は以下の記事を参照。

スポンサーリンク

組み込み演算子に対応する関数

operatorモジュールでは演算子に対応する関数が提供されている。代表的なものをいくつか紹介する。上述のように、ここに挙げるもの以外にもあるので一覧は公式ドキュメントの対応表を参照。

算術演算子

+演算子はoperator.add()で実現できる。operator.add(a, b)a + bと等価。

import operator

print(2 + 3)
# 5

print(operator.add(2, 3))
# 5

そのほか、-*, /, //演算子に対応する関数も提供されている。

print(operator.sub(2, 3))  # 2 - 3
# -1

print(operator.mul(2, 3))  # 2 * 3
# 6

print(operator.truediv(2, 3))  # 2 / 3
# 0.6666666666666666

print(operator.floordiv(2, 3))  # 2 // 3
# 0

リストなどのイテラブルオブジェクトの累積和を生成するitertools.accumulate()では適用する関数を引数で指定できるようになっており、operator.mul()を利用することで累積積を生成することが可能。

比較演算子

<==などの比較演算子に対応する関数も提供されている。

print(operator.lt(2, 3))  # 2 < 3
# True

print(operator.le(2, 3))  # 2 <= 3
# True

print(operator.gt(2, 3))  # 2 > 3
# False

print(operator.ge(2, 3))  # 2 >= 3
# False

print(operator.eq(2, 3))  # 2 == 3
# False

print(operator.ne(2, 3))  # 2 != 3
# True

論理演算子

ビット単位の論理演算子である&(AND)や|(OR), ^(XOR)などに対応する関数も提供されている。ここでは0bを使って2進数で整数intを表し、結果をbin()で2進数に変換して出力している。

print(bin(0b1100 & 0b1010))
# 0b1000

print(bin(operator.and_(0b1100, 0b1010)))
# 0b1000

print(bin(0b1100 | 0b1010))
# 0b1110

print(bin(operator.or_(0b1100, 0b1010)))
# 0b1110

print(bin(0b1100 ^ 0b1010))
# 0b110

print(bin(operator.xor(0b1100, 0b1010)))
# 0b110

そのほか、~(反転)やビットシフト<<, >>に対応する関数もある。

なお、operator.and_()operator.or_()という名前だが、ブール演算子のandorとは違うので注意。

print(bin(0b1100 and 0b1010))
# 0b1010

print(bin(0b1100 or 0b1010))
# 0b1100

andorでは左右のオブジェクトを真Trueか偽Falseか判定した上で、左か右のいずれかの値が返されるので上のような結果となる。詳細は以下の記事を参照。

Python3.8時点ではandorに対応する関数はない。

オブジェクトの要素を取得: operator.itemgetter()

operator.itemgetter()は対象となるオブジェクトの要素を取得する呼び出し可能オブジェクトを生成する。

[xxx]のようなインデックス指定に相当する処理を実行できる。

l = [0, 10, 20, 30, 40, 50]

print(l[3])
# 30

f = operator.itemgetter(3)
print(f(l))
# 30

operator.add()などとは異なり、operator.itemgetter()が生成するのは呼び出し可能オブジェクト。そこからさらに対象を括弧()で指定して呼び出すことで実行される。

()が連続して奇妙に感じるかもしれないが、続けて書くと以下のようになる。

print(operator.itemgetter(3)(l))
# 30

以降、動作を紹介するために()を連続した書き方を用いる場合がある。

通常の[]によるインデックス指定と同じく、負の値で後ろからの位置で指定することも可能。

print(l[-1])
# 50

print(operator.itemgetter(-1)(l))
# 50

スライスにも対応している。slice()関数を利用する。

print(l[1:4])
# [10, 20, 30]

print(operator.itemgetter(slice(1, 4))(l))
# [10, 20, 30]

print(l[1::2])
# [10, 30, 50]

print(operator.itemgetter(slice(1, None, 2))(l))
# [10, 30, 50]

operator.itemgetter()の引数には複数の値を指定可能。それぞれの結果を要素とするタプルが返される。

print(operator.itemgetter(0, slice(1, 4), -1)(l))
# (0, [10, 20, 30], 50)

print(type(operator.itemgetter(0, slice(1, 4), -1)(l)))
# <class 'tuple'>

operator.itemgetter()__getitem__()によってアイテムを取得している。リストやタプルなどのインデックス指定だけでなく、辞書dictのキー指定による値取得などにも対応している。

d = {'k1': 0, 'k2': 10, 'k3': 20}

print(d['k2'])
# 10

print(operator.itemgetter('k2')(d))
# 10

print(operator.itemgetter('k2', 'k1')(d))
# (10, 0)

operator.itemgetter()の具体的な利用例として、sorted()関数などの引数keyへの指定がある。詳細は以下の記事を参照。

オブジェクトの属性を取得: operator.attrgetter()

operator.attrgetter()は対象となるオブジェクトの属性を取得する呼び出し可能オブジェクトを生成する。

.xxxのような属性取得に相当する処理を実行できる。

日時情報を保持するdatetime.dateオブジェクトを例とする。

import datetime

dt = datetime.date(2001, 10, 20)
print(dt)
# 2001-10-20

print(type(dt))
# <class 'datetime.date'>

print(dt.year)
# 2001

operator.attrgetter()で属性を取得する呼び出し可能オブジェクトを生成できる。operator.itemgetter()と同様、複数の属性をまとめて取得可能。

f = operator.attrgetter('year')
print(f(dt))
# 2001

print(operator.attrgetter('year', 'month', 'day')(dt))
# (2001, 10, 20)

オブジェクトのメソッドを実行: operator.methodcaller()

operator.methodcaller()は対象となるオブジェクトのメソッドを実行する呼び出し可能オブジェクトを生成する。

s = 'xxxAyyyAzzz'

print(s.upper())
# XXXAYYYAZZZ

f = operator.methodcaller('upper')
print(f(s))
# XXXAYYYAZZZ

引数も指定可能。キーワード引数も指定できる。

print(s.split('A', maxsplit=1))
# ['xxx', 'yyyAzzz']

print(operator.methodcaller('split', 'A', maxsplit=1)(s))
# ['xxx', 'yyyAzzz']

operator.attrgetter()operator.methodcaller()operator.itemgetter()と同じくsorted()関数などの引数keyへの指定に利用されることがある。

スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事