実用的ではないと思います。ただやってみたかっただけです。
JavascriptやRustではおなじみのメソッドチェーン。例えばRustだとイテレータメソッドをひたすらつなげることができます。
let v: Vec<i32> = (0..10)
.map(|x| x + 2)
.filter(|x| x % 2 == 1)
.map(|x| x * 2)
.collect();
println!("result is {:?}", v);
// 出力は以下のようになる
// result is [6, 10, 14, 18, 22]
これをPythonで普通に書くとこんな感じ。
v = list(
map(lambda x: x * 2,
filter(lambda x: x % 2 == 1,
map(lambda x: x + 2, range(10))
)
)
)
print(f'result is {v}')
# 出力はRust版と同じ
# result is [6, 10, 14, 18, 22]
これはこれで全然いいんですけど、読みやすさのために改行+インデントでフォーマットしていくと、やたらとインデントが深くなってしまうのがちょっと嫌。あと先に適用する関数を後ろに(より内側に)書くのがメソッドチェーンの場合と逆センスなのも少しだけモヤっとする。
ということで、こんな感じのクラスを定義。
from collections.abc import Iterable
from typing import Callable, List
class DotChain(Iterable):
def __init__(self, it: Iterable):
self._it = it
def __iter__(self):
return self._it.__iter__()
def map(self, op: Callable):
return DotChain(map(op, self._it))
def filter(self, op: Callable):
return DotChain(filter(op, self._it))
def collect(self) -> List:
return list(self)
すると、メソッドチェーンっぽく書けるようになる。
v = DotChain(range(10)) \
.map(lambda x: x + 2) \
.filter(lambda x: x % 2 == 1) \
.map(lambda x: x * 2) \
.collect()
print(f'result is {v}')
# 出力はRust版、Python版と同じ
# result is [6, 10, 14, 18, 22]
改行をエスケープしないといけないのだけれど、書き方的にはかなりJavascriptやRustに近づいた。
はい、それだけです。