読者です 読者をやめる 読者になる 読者になる

Python の Promise 実装とその活用方法について / How to implement Promise by Python and how to use it

Python の Promise 実装とその活用方法について / How to implement Promise by Python and how to use it

機械学習や TensorFlow を使っていろいろデータの処理をしていると、アレしたあとにコレ、みたいな、データ処理をパイプラインのように処理したくなることがあります。
そんなとき JavaScript だと Promise という便利な書き方があるのですが、Python でできないもんかと探しているとその名も promise という便利なモジュールがあったのでちょっと遊んで見ました。

** Sorry, this note is Japanese only, but please take a look at some code snippets. Hope it helps you.

参考: GitHub - syrusakbary/promise: Ultra-performant Promise implementation in Python

そもそも Promise って・・・?

今さらですが。
Promise というのは、もともと E言語 とかいう言語で提唱された、並列処理の、いわばデザインパターンの一種だそうです。
ES6 で実装されたことで今となっては JavaScript でメジャーなようですが、Mozilla のリファレンスによると、以下のような説明がされています。

A Promise is a proxy for a value not necessarily known when the promise is created. It allows you to associate handlers with an asynchronous action’s eventual success value or failure reason. This lets asynchronous methods return values like synchronous methods: instead of immediately returning the final value, the asynchronous method returns a promise to supply the value at some point in the future.
引用元:Promise - JavaScript | MDN

  • 並列処理を組むときに欠かせない、非同期処理を抽象化したオブジェクトを定義したもの
  • それを実際に実行して成功時・失敗時のイベントハンドラを登録することができる
  • Promise オブジェクトのメソッドは、非同期処理の結果ではなく、常に Promise オブジェクトを返す

って感じでいいのかな・・・?
Promise の仕様と API は明確に定義されているので、何も JavaScript だけのものではなく、同じものを実装すれば任意の言語で使えるはず。
そこで、Python で Promise の実装がされてないか調べて見たら、冒頭の promise というモジュールがありました。

Python の promise モジュールのインストール

pip で簡単にインストールできます。

$ pip install promise  

promise を使った Python の非同期プログラミングのサンプルコード

まず、以下のような関数を定義して見ます。

from promise import Promise
def async_function():
    msg = 'Hello, async function with promise.'
    def myfunc(resolve, reject):
        def signal_handler(*args):
                resolve(msg)
        signal.signal(signal.SIGALRM, signal_handler)
        signal.setitimer(signal.ITIMER_REAL, 5)
    return Promise(myfunc)

なんてことはない、signal.SIGALRM のタイミングで、signal_handler を実行する、いわば、JavaScript の setTimeout のような処理です。
ただちょっと普通と違うのは、この async_function は、Promise というオブジェクトを返すところです。
Promise オブジェクトは、then と catch というメソッドをもち、

Promise.then(成功時に実行するイベントハンドラ=resolve).catch(失敗時に実行するイベントハンドラ=reject)  

という形で実行することができます。なので、

>>> async_function().then(lambda x: print('Here is then, ', x)).catch(lambda x: print(x))

という具合に、resolve に lambda 関数を与えると、myfunc が実行され、5秒待ってから resolve 、つまり lambda 関数で定義した処理が実行されます。

<promise.promise.Promise object at 0x10964b9a0>
>>> Here is then,  Hello, async function with promise.

ここで、lambda 関数をワザと間違えてみると …

>>> async_function().then(lambda x: print('Here is then, ', y)).catch(lambda x: print('Failed. ', x))
<promise.promise.Promise object at 0x10964b8d0>
>>> Failed. name 'y' is not defined

という具合に、catch のほう、つまり、reject が実行されていることがわかります。

Python の非同期処理実装は他にも色々ある

実は、Python って promise に限らず、他にも非同期処理の書き方があるらしく、特に 3.x あたりから concurrent.futures や asyncio といった、ビルトインの並列処理を扱うモジュールが用意されているようです。

というわけで、この辺の Python の非同期処理はもうちょっと勉強してみようと思います。

Python 関連の他の記事

datalove.hatenadiary.jp datalove.hatenadiary.jp datalove.hatenadiary.jp datalove.hatenadiary.jp