Pythonでdecorator
1999 ワード
@decoratorは関数機能の動的増加を実現できますが、@decoratorの「改造」後の関数は、元の関数に比べて機能が少し多い以外に、他に異なるところはありませんか?
栗1:decoratorがない場合、関数名を印刷:
結果:f 1
栗2:decoratorがある場合、関数名を印刷:
結果:wrapper
以上の栗から,関数名が元の関数f 2ではなく,アクセラレータ関数内部で定義されたwrapperが返され,関数名に依存するコードには失効することが分かる.decoratorは関数の__も変更しましたdoc__などのフォントスタイルや効果を適用します.呼び出し元が@decoratorの「改造」を経た関数が1つも見えないようにするには、元の関数のいくつかの属性を新しい関数にコピーする必要があります.
結果:f 2
However、このようにdecoratorを書くのは不便です.元の関数のすべての必要な属性を新しい関数に1つずつコピーするのは難しいので、Pythonに内蔵されているfunctoolsはこの「コピー」のタスクを自動化することができます.
結果:f 2
タスク:前節コードに,@functools.wrapsは、元の関数のプロパティが参照時に変化しないようにします.
結果:factorial
注:カッコに元の関数名がない場合@functools.wraps(f)は、次のようにエラーを報告します.
AttributeError: ‘functools.partial’ object has no attribute ‘name’
がんばって!学習リンク:https://www.imooc.com/code/6067
栗1:decoratorがない場合、関数名を印刷:
def f1(x):
pass
print(f1.__name__)
結果:f 1
栗2:decoratorがある場合、関数名を印刷:
def log(f):
def wrapper(*args, **kw):
print('call...')
return f(*args, **kw)
return wrapper
@log
def f2(x):
pass
print(f2.__name__)
結果:wrapper
以上の栗から,関数名が元の関数f 2ではなく,アクセラレータ関数内部で定義されたwrapperが返され,関数名に依存するコードには失効することが分かる.decoratorは関数の__も変更しましたdoc__などのフォントスタイルや効果を適用します.呼び出し元が@decoratorの「改造」を経た関数が1つも見えないようにするには、元の関数のいくつかの属性を新しい関数にコピーする必要があります.
def log(f):
def wrapper(*args, **kw):
print('call...')
return f(*args, **kw)
wrapper.__name__ = f.__name__
wrapper.__doc__ = f.__doc__
return wrapper
@log
def f2(x):
pass
print(f2.__name__)
結果:f 2
However、このようにdecoratorを書くのは不便です.元の関数のすべての必要な属性を新しい関数に1つずつコピーするのは難しいので、Pythonに内蔵されているfunctoolsはこの「コピー」のタスクを自動化することができます.
import functools
def log(f):
@functools.wraps(f)
def wrapper(*args, **kw):
print('call...')
return f(*args, **kw)
return wrapper
@log
def f2(x):
pass
print(f2.__name__)
結果:f 2
タスク:前節コードに,@functools.wrapsは、元の関数のプロパティが参照時に変化しないようにします.
import time, functools
from functools import reduce
def performance(unit):
def perf_decorator(f):
@functools.wraps(f)
def wrapper(*args, **kw):
print('call'+' '+'%s() in %s%s' % (f.__name__, time.time(), unit))
return wrapper
return perf_decorator
@performance('ms')
def factorial(n):
return reduce(lambda x,y: x*y, range(1, n+1))
print(factorial.__name__)
結果:factorial
注:カッコに元の関数名がない場合@functools.wraps(f)は、次のようにエラーを報告します.
AttributeError: ‘functools.partial’ object has no attribute ‘name’
がんばって!学習リンク:https://www.imooc.com/code/6067