に | 後 |
---|---|
| |
仕組み
既にお気付きのとおり、 yieldを<<に置き換えました。 Pythonでは標準ツールでこれを行うことができないため、バイトコードを変更する必要があります。 単純な作業には、 Byteplayモジュールを使用します。 2つの単純な関数のバイトコードを見てみましょう。
| |
| |
したがって、この状況のために単純なパッチャーを作成します。
| |
これで、 gen関数のバイトコードとほぼ同じバイトコードが得られ、それをシフトに適用して結果を確認します。
| |
結果は同じです。 一般的な状況のコードはgithubで表示できます 。 バイトコードの詳細については、公式ドキュメントをご覧ください。 それまでの間、竜巻に戻ります。 既製のshortgenデコレータを取ります。 そして、簡単なハンドラーを書きます。
def fetch(callback): callback(1) class Handler(BaseHandler): @asynchronous @gen.engine @shortgen def get(self): result << gen.Task(fetch)
コードは少し良くなりましたが、まだgen.Taskで呼び出しを手動でラップする必要があるため、このプロセスを自動化する別のデコレータを作成しましょう。
def fastgen(fnc): return partial(gen.Task, fnc) @fastgen def fetch(callback): callback(1) class Handler(BaseHandler): @asynchronous @gen.engine @shortgen def get(self): result << fetch()
今ではすべてがかなりまともに見えますが、サードパーティのライブラリでどのように機能しますか? しかし、何もありませんので、パッチを適用する必要があります! いいえ、今はバイトコードにパッチを適用しませんが、サルパッチを使用します。 古いコードを壊さないために、必要なクラスの__getattribute__を次のように置き換えます。
def getattribute(self, name): attr = None if name.find('_e') == len(name) - 2: attr = getattr(self, name[:-2]) if hasattr(attr, '__call__'): return fastgen(attr) else: return super(self.__class__, self).__getattribute__(name)
パッチが適用されたオブジェクトに属性(たとえば、 find_e (古いコードを壊さないように接尾辞_eが追加された))がない場合、 fasttgenデコレータでラップされた検索属性を返します 。
そして今、たとえば、asyncmongoのコードは次のようになります。
from asyncmongo.cursor import Cursor Cursor.__getattribute__ = getattribute class Handler(BaseHandler): @asynchronous @gen.engine @shortgen def get(self): result, status << self.db.posts.find_e({'name': 'post'})
使い方
まず、結果のモジュールをインストールします。
pip install -e git+https://github.com/nvbn/evilshortgen.git#egg=evilshortgen
次に、必要なクラスにパッチを適用します。
from evilshortgen import shortpatch shortpatch(Cls1, Cls2, Cls3)
デコレータで独自の非同期メソッドと非同期関数をラップします。
from evilshortgen import fastgen @fastgen def fetch(id, callback): return callback(id)
そして、ハンドラーを使用します。
from evilshortgen import shortgen class Handler(BaseHandler): @asynchronous @gen.engine @shortgen def get(self, id): data << fetch(12) num, user << Cls1.fetch()
既知の問題
呼び出しでは、変数の値のみを設定できます。
a << fetch() # self.a << fetch() #
複雑な解凍はサポートされていません。
a, b << fetch() # (a, b), c << fetch() #
参照資料
GitHubのEvilshortgen
バイトコードの詳細
バイトプレイ