含まれるもの:
1、decorators
2、functools
まず、tornado で使用されるデコレータ
1、@tornado.web.authenticated を見てみましょう
引用
これでメソッドを修飾して要求しますユーザーがログインしていることを確認します。
Python コード
def authenticated(method): """Decorate methods with this to require that the user be logged in.""" @functools.wraps(method) def wrapper(self, *args, **kwargs): if not self.current_user: if self.request.method in ("GET", "HEAD"): url = self.get_login_url() if "?" not in url: if urlparse.urlsplit(url).scheme: # if login url is absolute, make next absolute too next_url = self.request.full_url() else: next_url = self.request.uri url += "?" + urllib.urlencode(dict(next=next_url)) self.redirect(url) return raise HTTPError(403) return method(self, *args, **kwargs) return wrapper
次のコードでは、ユーザーのログイン方法を検証する必要があります。このデコレーターを使用すると、繰り返し行われる多くの検証コードを簡素化できます。 @tornado.web.authenticated をメソッドに追加するだけでOKです。
2. @tornado.web.asynchronous
Python コード
def asynchronous(method): @functools.wraps(method) def wrapper(self, *args, **kwargs): if self.application._wsgi: raise Exception("@asynchronous is not supported for WSGI apps") self._auto_finish = False with stack_context.ExceptionStackContext( self._stack_context_handle_exception): return method(self, *args, **kwargs) return wrapper
このデコレーターは self._auto_finish を False に設定します。
次に、単一インタレスト モード デコレーターを作成しましょう:
Python コード
def singleton(cls): instances = {} def get_instance(): if cls not in instances: instances[cls] = cls() return instances[cls] return get_instance @singleton class Foo: def __init__(self): pass class Bar: def __init__(self): pass f = Foo() m = Foo() print f,m,f == m a = Bar() b = Bar() print a,b,a == b
結果は次のとおりです:
<__main__.Foo インスタンス at 0x103152c20<__main__.Foo インスタンス at 0x103152c20> True
< __main__ .Bar 0x103152c68 のインスタンス> <__main__.Bar 0x103152cb0 のインスタンス> False
@singleton このデコレータはクラスのシングルトン モードを実装し、クラスが 1 回だけインスタンス化されるようにします。
デコレータを使用してパラメータとメソッドの戻り結果を確認します:
Python コード
#-*-coding:utf-8-*- def accepts(*types): def check_accepts(f): # assert len(types) == f.func_code.co_argcount def new_f(*args, **kwds): for (a, t) in zip(args, types): assert isinstance(a, t), \ "arg %r does not match %s" % (a,t) return f(*args, **kwds) new_f.func_name = f.func_name return new_f return check_accepts def returns(rtype): def check_returns(f): def new_f(*args, **kwds): result = f(*args, **kwds) assert isinstance(result, rtype), \ "return value %r does not match %s" % (result,rtype) return result new_f.func_name = f.func_name return new_f return check_returns @accepts(int, (int,float)) @returns((int,float)) def func(arg1, arg2): return arg1 * arg2 print func(1,2.0)
Python コード
def check_param_isvalid(): def check(method): def check_param(*args,**kwargs): for a in args: assert isinstance(a, int),"arg %r does not match %s" % (a,int) assert a > 100000,"arg %r must gt 100000" % a return method(*args, **kwargs) return check_param return check @check_param_isvalid() def foo(*args): print args foo(200000,5000)
result:
assert a > 100000,"arg %r should gt 100 000" %a
AssertionError: arg 5000 must gt 100000
Quote
設計目標:
新しい構文は、ユーザー定義の呼び出し可能オブジェクトや既存の組み込みの classmethod() および staticmethod() を含む任意のラッパーで機能する必要がありますこれこの要件は、デコレータ構文がラッパー コンストラクターへの引数の受け渡しをサポートする必要があることも意味します
* 定義ごとに複数のラッパーを処理します
* 何が起こっているかを明確にする 少なくとも、新しいユーザーがそれを作成するときに安全に無視できることは明らかである必要があります。独自のコード
* 「一度説明すると覚えやすい」構文であること
* 将来の拡張を難しくしないこと
* それを使用するプログラムは、非常に頻繁に使用することが期待されるため、入力しやすいこと
* ではないコードをすばやくスキャンすることはより困難になりますが、すべての定義、特定の定義、または関数が受け入れる引数を検索するのは簡単でなければなりません
* 言語に依存するエディターやその他の「おもちゃ」などの二次サポート ツールを不必要に複雑にしないでください。パーサー ツールが世に出ています [12]"
* 将来のコンパイラーがデコレーター用に最適化できるようにします。Python 用の JIT コンパイラーがいつか登場することを期待して、関数定義の前にデコレーターの構文が必要になる傾向があります
* move現在隠されている機能の終わりから、もっと前面に出てくるところまで [13]