この記事は Pythonのコードを短く簡潔に書くテクニック Advent Calendar 2017 の24日目です。
はじめに
Pythonでは自作クラスの演算子をオーバーロードできます。
演算子を使うことで通常のメソッド呼び出しより短く書けるだけでなく、直感的でわかりやすいコードになる場合もあります。
Command('ls').pipe('cat').redirect_to('out.txt')
↓
Command('ls') | 'cat' > 'out.txt'
標準モジュールで演算子を使っている例
先ずは標準モジュールで演算子を使っている例を紹介します。
pathlib.Pathの"/"
Python3.4から追加でされた pathlib.Path では joinpath() で2つのパスを連結できますが、演算子"/" でも同じことができます。
>>> from pathlib import Path
>>> Path('/aaa/bbb').joinpath('ccc/ddd')
PosixPath('/aaa/bbb/ccc/ddd')
>>> from pathlib import Path
>>> Path('/aaa/bbb') / 'ccc/ddd'
PosixPath('/aaa/bbb/ccc/ddd')
strの"%"
文字列の書式化には現在は str.format() がよく使われていますが、それ以前は演算子"%"を使ったprintf形式の文字列書式化が使われていました。
これを文字列専用の特殊な構文だと思っている人がいるかもしれませんが、実は演算子"%"を使っているだけなんです。
>>> 'Hello %s' % ('Python',)
'Hello Python'
>>> 'Hello %s'.__mod__(('Python',))
'Hello Python'
自作クラスで演算子を使えるようにするには
自作クラスに特殊メソッドを実装することで演算子が使えるようになります。
例えば二項算術演算子を使えるようにするには以下の特殊メソッドを実装します。
演算子 | 特殊メソッド | 備考 |
---|---|---|
+ |
__add__ |
|
- |
__sub__ |
|
* |
__mul__ |
|
@ |
__matmul__ |
バージョン 3.5 で追加. |
/ |
__truediv__ |
※2.7の仕様はこちらを参照 |
// |
__floordiv__ |
|
% |
__mod__ |
|
** |
__pow__ |
|
<< |
__lshift__ |
|
>> |
__rshift__ |
|
& |
__and__ |
|
^ |
__xor__ |
|
| |
__or__ |
実例:subprocessでパイプとリダイレクトを実装する
subprocessをラップしてシェルスクリプトのようにパイプ"|"やリダイレクト">"を使えるようにしてみます。
先ずはsubprocessをラップしたクラスを普通に作成します。
ここではまだ演算子は実装しません。
import shlex
import subprocess
from subprocess import PIPE
class Command:
def __init__(self, command, stdin=PIPE):
self.p = subprocess.Popen(shlex.split(command),
shell=True,
stdin=stdin,
stdout=PIPE)
def pipe(self, command):
next_command = Command(command, self.p.stdout)
return next_command
def redirect_to(self, file):
with open(file, 'w') as f:
for line in self.p.stdout:
f.write(line.decode())
この状態ではパイプやリダイレクトは以下のようなメソッド呼び出しをしなければなりません。
Command('ls').pipe('cat').redirect_to('out.txt')
次に以下のメソッドをCommandクラスに追加します。
def __or__(self, command):
return self.pipe(command)
def __gt__(self, file):
return self.redirect_to(file)
以下のように演算子でパイプとリダイレクトが使えるようになり、シェルスクリプトのような記述ができるようになります。
Command('ls') | 'cat' > 'out.txt'
参考
-
Python3ドキュメント
- 言語リファレンス
-
- データモデル
-
- ライブラリーリファレンス
- 言語リファレンス
-
Qiita