operator – ビルトイン演算子に対する関数インタフェース

目的:ビルトイン演算子に対する関数インタフェース
利用できるバージョン:1.4 以上

イテレータを折に触れて使用する関数プログラミングはシンプルな表現のために小さな関数を作成するように要求します。それは lambda 関数として表現されるときもありますが、幾つかの演算では全く独自の関数で実装される必要はありません。 operator モジュールはシーケンスやディクショナリの操作と同様に算術や比較演算のためにビルトイン演算に対応する関数を定義します。

論理演算

真偽値の評価、逆の真偽値を作成するための否定やそういった値が等価かどうかを確認するための比較オブジェクトを決定する関数があります。

from operator import *

a = -1
b = 5

print 'a =', a
print 'b =', b
print

print 'not_(a)     :', not_(a)
print 'truth(a)    :', truth(a)
print 'is_(a, b)   :', is_(a,b)
print 'is_not(a, b):', is_not(a,b)

not は Python のキーワードなので not_() は最後にアンダースコアが続きます。 truth()if 文の式がテストされるときと同じロジックを適用します。 is_()is キーワードにより使用される同じチェックを実装します。そして is_not() は同じテストを行い逆の内容を返します。

$ python operator_boolean.py
a = -1
b = 5

not_(a)     : False
truth(a)    : True
is_(a, b)   : False
is_not(a, b): True

比較演算子

実用に十分な比較演算子が全てサポートされています。

from operator import *

a = 1
b = 5.0
print

print 'a =', a
print 'b =', b
for func in (lt, le, eq, ne, ge, gt):
    print '%s(a, b):' % func.__name__, func(a, b)

それらの関数群は <, <=, ==, >=> を使用する式の構文と等価です。

$ python operator_comparisons.py

a = 1
b = 5.0
lt(a, b): True
le(a, b): True
eq(a, b): False
ne(a, b): True
ge(a, b): False
gt(a, b): False

算術演算子

数値の値を操作するために算術演算子もサポートされています。

from operator import *

a = -1
b = 5.0
c = 2
d = 6

print 'a =', a
print 'b =', b
print 'c =', c
print 'd =', d

print '\nPositive/Negative:'
print 'abs(a):', abs(a)
print 'neg(a):', neg(a)
print 'neg(b):', neg(b)
print 'pos(a):', pos(a)
print 'pos(b):', pos(b)

print '\nArithmetic:'
print 'add(a, b)     :', add(a, b)
print 'div(a, b)     :', div(a, b)
print 'div(d, c)     :', div(d, c)
print 'floordiv(a, b):', floordiv(a, b)
print 'floordiv(d, c):', floordiv(d, c)
print 'mod(a, b)     :', mod(a, b)
print 'mul(a, b)     :', mul(a, b)
print 'pow(c, d)     :', pow(c, d)
print 'sub(b, a)     :', sub(b, a)
print 'truediv(a, b) :', truediv(a, b)
print 'truediv(d, c) :', truediv(d, c)

print '\nBitwise:'
print 'and_(c, d)  :', and_(c, d)
print 'invert(c)   :', invert(c)
print 'lshift(c, d):', lshift(c, d)
print 'or_(c, d)   :', or_(c, d)
print 'rshift(d, c):', rshift(d, c)
print 'xor(c, d)   :', xor(c, d)

Note

$ python operator_math.py
a = -1
b = 5.0
c = 2
d = 6

Positive/Negative:
abs(a): 1
neg(a): 1
neg(b): -5.0
pos(a): -1
pos(b): 5.0

Arithmetic:
add(a, b)     : 4.0
div(a, b)     : -0.2
div(d, c)     : 3
floordiv(a, b): -1.0
floordiv(d, c): 3
mod(a, b)     : 4.0
mul(a, b)     : -5.0
pow(c, d)     : 64
sub(b, a)     : 6.0
truediv(a, b) : -0.2
truediv(d, c) : 3.0

Bitwise:
and_(c, d)  : 2
invert(c)   : -3
lshift(c, d): 128
or_(c, d)   : 6
rshift(d, c): 1
xor(c, d)   : 4

シーケンス演算子

シーケンスで動作する演算子は4つのグループに分けられます。それらはシーケンスの構築、要素の検索、中身へのアクセス、シーケンスから要素を削除するものです。

from operator import *

a = [ 1, 2, 3 ]
b = [ 'a', 'b', 'c' ]

print 'a =', a
print 'b =', b

print '\nConstructive:'
print '  concat(a, b):', concat(a, b)
print '  repeat(a, 3):', repeat(a, 3)

print '\nSearching:'
print '  contains(a, 1)  :', contains(a, 1)
print '  contains(b, "d"):', contains(b, "d")
print '  countOf(a, 1)   :', countOf(a, 1)
print '  countOf(b, "d") :', countOf(b, "d")
print '  indexOf(a, 5)   :', indexOf(a, 1)

print '\nAccess Items:'
print '  getitem(b, 1)            :', getitem(b, 1)
print '  getslice(a, 1, 3)        :', getslice(a, 1, 3)
print '  setitem(b, 1, "d")       :', setitem(b, 1, "d"), ', after b =', b
print '  setslice(a, 1, 3, [4, 5]):', setslice(a, 1, 3, [4, 5]), ', after a =', a

print '\nDestructive:'
print '  delitem(b, 1)    :', delitem(b, 1), ', after b =', b
print '  delslice(a, 1, 3):', delslice(a, 1, 3), ', after a =', a

そういった演算子には setitem()delitem() のように特定位置のシーケンスを変更して値を返さないものがあります。

$ python operator_sequences.py
a = [1, 2, 3]
b = ['a', 'b', 'c']

Constructive:
  concat(a, b): [1, 2, 3, 'a', 'b', 'c']
  repeat(a, 3): [1, 2, 3, 1, 2, 3, 1, 2, 3]

Searching:
  contains(a, 1)  : True
  contains(b, "d"): False
  countOf(a, 1)   : 1
  countOf(b, "d") : 0
  indexOf(a, 5)   : 0

Access Items:
  getitem(b, 1)            : b
  getslice(a, 1, 3)        : [2, 3]
  setitem(b, 1, "d")       : None , after b = ['a', 'd', 'c']
  setslice(a, 1, 3, [4, 5]): None , after a = [1, 4, 5]

Destructive:
  delitem(b, 1)    : None , after b = ['a', 'c']
  delslice(a, 1, 3): None , after a = [1]

インプレース演算子

標準演算子に加えて、多くのオブジェクト型が += のような特種な演算子を通して入力データを直接書き換える “インプレース” 処理をサポートします。インプレース処理と同等の関数もあります。

from operator import *

a = -1
b = 5.0
c = [ 1, 2, 3 ]
d = [ 'a', 'b', 'c']
print 'a =', a
print 'b =', b
print 'c =', c
print 'd =', d
print

a = iadd(a, b)
print 'a = iadd(a, b) =>', a
print

c = iconcat(c, d)
print 'c = iconcat(c, d) =>', c

このサンプルはインプレース処理を行う関数を少しだけ紹介します。その他の関数の詳細は標準ライブラリを参照してください。

$ python operator_inplace.py
a = -1
b = 5.0
c = [1, 2, 3]
d = ['a', 'b', 'c']

a = iadd(a, b) => 4.0

c = iconcat(c, d) => [1, 2, 3, 'a', 'b', 'c']

属性と要素の “ゲッタ”

operator モジュールで最も独特な機能の1つは ゲッタ の概念です。オブジェクトの属性、又はシーケンスから要素を取り出すために実行時に構築された呼び出し可能オブジェクトです。ゲッタは lambda 又は Python 関数よりもオーバーヘッドを少なくする目的でイテレータかジェネレータと一緒に使用すると特に便利です。

from operator import *

class MyObj(object):
    """example class for attrgetter"""
    def __init__(self, arg):
        super(MyObj, self).__init__()
        self.arg = arg
    def __repr__(self):
        return 'MyObj(%s)' % self.arg

l = [ MyObj(i) for i in xrange(5) ]
print l
g = attrgetter('arg')
vals = [ g(i) for i in l ]
print vals

属性のゲッタは lambda x, n='attrname': getattr(x, n) のように動作します。

$ python operator_attrgetter.py
[MyObj(0), MyObj(1), MyObj(2), MyObj(3), MyObj(4)]
[0, 1, 2, 3, 4]

要素のゲッタは lambda x, y=5: x[y] のように動作します。

from operator import *

print 'Dictionaries:'
l = [ dict(val=i) for i in xrange(5) ]
print l
g = itemgetter('val')
vals = [ g(i) for i in l ]
print vals

print
print 'Tuples:'
l = [ (i, i*2) for i in xrange(5) ]
print l
g = itemgetter(1)
vals = [ g(i) for i in l ]
print vals

要素のゲッタはシーケンスと同様にマッピングされて動作します。

$ python operator_itemgetter.py
Dictionaries:
[{'val': 0}, {'val': 1}, {'val': 2}, {'val': 3}, {'val': 4}]
[0, 1, 2, 3, 4]

Tuples:
[(0, 0), (1, 2), (2, 4), (3, 6), (4, 8)]
[0, 2, 4, 6, 8]

演算子とカスタムクラスを組み合わせる

operator モジュールの関数は演算のために標準の Python インタフェース経由で動作します。そのため、ビルトイン型と同様にユーザ定義クラスで動作します。

from operator import *

class MyObj(object):
    """Example for operator overloading"""
    def __init__(self, val):
        super(MyObj, self).__init__()
        self.val = val
        return
    def __str__(self):
        return 'MyObj(%s)' % self.val
    def __lt__(self, other):
        """compare for less-than"""
        print 'Testing %s < %s' % (self, other)
        return self.val < other.val
    def __add__(self, other):
        """add values"""
        print 'Adding %s + %s' % (self, other)
        return MyObj(self.val + other.val)

a = MyObj(1)
b = MyObj(2)

print 'Comparison:'
print lt(a, b)

print '\nArithmetic:'
print add(a, b)

それぞれの演算子で使用される特殊メソッドの完全なリストは Python リファレンスガイドを参照してください。

$ python operator_classes.py
Comparison:
Testing MyObj(1) < MyObj(2)
True

Arithmetic:
Adding MyObj(1) + MyObj(2)
MyObj(3)

型チェック

実際の演算子に加えて、マッピング、数値やシーケンスのデータ型のためにテスト API 準拠の関数があります。

from operator import *

class NoType(object):
    """Supports none of the type APIs"""
    
class MultiType(object):
    """Supports multiple type APIs"""
    def __len__(self):
        return 0
    def __getitem__(self, name):
        return 'mapping'
    def __int__(self):
        return 0

o = NoType()
t = MultiType()

for func in (isMappingType, isNumberType, isSequenceType):
    print '%s(o):' % func.__name__, func(o)
    print '%s(t):' % func.__name__, func(t)

サンプルのテストはインタフェースが厳密に定義されていないので完璧ではありません。しかし、そういったインタフェースの何がサポートされているかのアイディアを与えてくれます。

$ python operator_typechecking.py
isMappingType(o): False
isMappingType(t): True
isNumberType(o): False
isNumberType(t): True
isSequenceType(o): False
isSequenceType(t): True

abc はコレクション型の API を定義する 抽象基底クラス を含みます。

See also

operator
本モジュールの標準ライブラリドキュメント
functools
関数プログラミングツールで、拡張比較(rich comparison)メソッドをクラスに追加する total_ordering() デコレータを提供します
itertools
イテレータの操作
Bookmark and Share