ホームページ  >  記事  >  ウェブフロントエンド  >  Python デコレータと functools_html/css_WEB-ITnose

Python デコレータと functools_html/css_WEB-ITnose

WBOY
WBOYオリジナル
2016-06-24 11:22:421211ブラウズ

... デコレータとして使用できる人

デコレータとして使用できる人

関数の変更

    デコレータの最も一般的な使用法は、新しく定義された関数を変更することです。コンテキスト マネージャーは 0x0d で説明されています。主に
  1. Update のためのコンテキスト マネージャーです。その後の作業を適切に完了します

    、デコレーターは通常、関数の動作やプロパティを拡張するために使用されます:

    @decorator@wrapdef func():    pass
    def func():    passfunc = decorator(wrap(func))
  2. クラスを変更する
  3. Python 3.0 では、関数の装飾に加えて、新しく定義されたクラスの装飾が追加されました ( PEP 3129)、ただし、カテゴリ属性の変更はメタクラスまたは継承を通じて実現でき、新しく追加されたカテゴリ デコレータは Jython と IronPython を考慮したものですが、その構文は依然として非常に一貫しています:

    def log(func):    def wraper():        print("INFO: Starting {}".format(func.__name__))        func()        print("INFO: Finishing {}".format(func.__name__))        return wraper@logdef run():    print("Running run...")run()
    INFO: Starting runRunning run...INFO: Finishing run
  4. Decorator としてのクラス

上の 2 つの例は両方とも、関数をデコレータとして使用します。これは、関数を呼び出すことができる (呼び出し可能な) デコレータ(wrap(func)) であるためです。関数に加えて、呼び出し可能なクラスも定義できます。__call__ メソッドを追加するだけです。

from time import sleep, timedef timer(Cls):    def wraper():        s = time()        obj = Cls()        e = time()        print("Cost {:.3f}s to init.".format(e - s))        return obj    return wraper@timerclass Obj:    def __init__(self):        print("Hello")        sleep(3)        print("Obj")o = Obj()
HelloObjCost 3.005s to init.

パラメータを渡す 実際の使用では、デコレータにパラメータを渡す必要がある場合や、デコレータにパラメータを渡す必要がある場合があります。変更された関数 (またはクラス)。構文規則によれば、デコレータ @decorator 内のデコレータが呼び出し可能である限り、decorator(123) が新しい呼び出し可能な関数を返すのは妥当です。上記の @HTML('html') を例に挙げます。デコレータにパラメータを渡す方法を示す例として、flask のルート デコレータを使用します。

class HTML(object):    """ Baking HTML Tags! """    def __init__(self, tag="p"):        print("LOG: Baking Tag <{}>!".format(tag))        self.tag = tag    def __call__(self, func):        return lambda: "<{0}>{1}</{0}>".format(self.tag, func(), self.tag)    @HTML("html")@HTML("body")@HTML("div")def body():    return "Hello"print(body())
LOG: Baking Tag <html>!LOG: Baking Tag <body>!LOG: Baking Tag <div>!<html><body><div>Hello</div></body></html>

変更された関数にパラメータを渡すことは、デコレータがどのように動作するかによって異なります。上記の例のように実行されない場合、関数は変更されるだけです。何も処理せずにそのまま返します (関数を通常の値として扱うだけです):

RULES = {}def route(rule):    def decorator(hand):        RULES.update({rule: hand})        return hand    return decorator    @route("/")def index():    print("Hello world!")def home():    print("Welcome Home!")home = route("/home")(home)index()home()print(RULES)
Hello world!Welcome Home!{'/': <function index at 0x10706f730>, '/home': <function home at 0x10706f8c8>}

デコレーター内で実行する必要がある場合は、少し変更する必要があります:

@route("/login")def login(user = "user", pwd = "pwd"):    print("DB.findOne({{{}, {}}})".format(user, pwd))login("hail", "python")
DB.findOne({hail, python})

functools

デコレータは関数 (またはクラス) をラップして返します: func =decorator(func)。上記の HTML デコレータを例にとると、元の関数 (またはクラス) の一部の情報を変更できます:

def log(f):    def wraper(*args, **kargs):        print("INFO: Start Logging")        f(*args, **kargs)        print("INFO: Finish Logging")    return wraper@logdef run(hello = "world"):    print("Hello {}".format(hello))run("Python")
INFO: Start LoggingHello PythonINFO: Finish Logging

Because body = HTML("body")(body)、および HTML("body").__call__() はラムダ関数を返すため、ボディはラムダに置き換えられています。これらはすべて実行可能な関数ですが、最初に定義されたボディの一部の属性は異なります。 __doc__/ __name__/ __module__ などは置き換えられています (この場合、__module__ はすべて同じファイル内にあるため変更されていません)。この問題を解決するために、Python は、update_wrapper とラップ メソッド (ソース コード) を含む functools 標準ライブラリを提供します。その中で、update_wrapper は、デコレーターで返された関数に元の関数の情報を割り当てるために使用されます:

@HTML("body")def body():    """ return body content """    return "Hello, body!"print(body.__name__)print(body.__doc__)
LOG: Baking Tag <body>!<lambda>None

興味深いのは、update_wrapper 自体の使用法がデコレーターと非常に似ているため、functools.wraps は functools.partial を使用することです。 (プログラミングの関数 Partial application を思い出してください!) それをデコレータに変えます:

from functools import update_wrapper"""functools.update_wrapper(wrapper, wrapped[, assigned][, updated])"""class HTML(object):    """ Baking HTML Tags! """    def __init__(self, tag="p"):        print("LOG: Baking Tag <{}>!".format(tag))        self.tag = tag    def __call__(self, func):        wraper = lambda: "<{0}>{1}</{0}>".format(self.tag, func(), self.tag)        update_wrapper(wraper, func)        return wraper        @HTML("body")def body():    """ return body content! """    return "Hello, body!"print(body.__name__)print(body.__doc__)
LOG: Baking Tag <body>!body        return body content!

リファレンス

Python デコレータの関数プログラミング

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。