我如何在Python中制作两个装饰器来完成以下操作?
@make_bold
@make_italic
def say():
return "Hello"
调用say()应返回:
"<b><i>Hello</i></b>"
我如何在Python中制作两个装饰器来完成以下操作?
@make_bold
@make_italic
def say():
return "Hello"
调用say()应返回:
"<b><i>Hello</i></b>"
当前回答
当然,您也可以从decorator函数返回lambdas:
def makebold(f):
return lambda: "<b>" + f() + "</b>"
def makeitalic(f):
return lambda: "<i>" + f() + "</i>"
@makebold
@makeitalic
def say():
return "Hello"
print say()
其他回答
查看文档以了解装饰器是如何工作的。以下是您的要求:
from functools import wraps
def makebold(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
return "<b>" + fn(*args, **kwargs) + "</b>"
return wrapper
def makeitalic(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
return "<i>" + fn(*args, **kwargs) + "</i>"
return wrapper
@makebold
@makeitalic
def hello():
return "hello world"
@makebold
@makeitalic
def log(s):
return s
print hello() # returns "<b><i>hello world</i></b>"
print hello.__name__ # with functools.wraps() this returns "hello"
print log('hello') # returns "<b><i>hello</i></b>"
用不同数量的参数修饰函数:
def frame_tests(fn):
def wrapper(*args):
print "\nStart: %s" %(fn.__name__)
fn(*args)
print "End: %s\n" %(fn.__name__)
return wrapper
@frame_tests
def test_fn1():
print "This is only a test!"
@frame_tests
def test_fn2(s1):
print "This is only a test! %s" %(s1)
@frame_tests
def test_fn3(s1, s2):
print "This is only a test! %s %s" %(s1, s2)
if __name__ == "__main__":
test_fn1()
test_fn2('OK!')
test_fn3('OK!', 'Just a test!')
结果:
Start: test_fn1
This is only a test!
End: test_fn1
Start: test_fn2
This is only a test! OK!
End: test_fn2
Start: test_fn3
This is only a test! OK! Just a test!
End: test_fn3
Python装饰器为另一个函数添加了额外的功能
斜体装饰符可以如下所示
def makeitalic(fn):
def newFunc():
return "<i>" + fn() + "</i>"
return newFunc
注意,函数是在函数内部定义的。它基本上是用新定义的函数替换函数。例如,我有这门课
class foo:
def bar(self):
print "hi"
def foobar(self):
print "hi again"
现在,我希望两个函数在完成后和完成前都打印“---”。我可以在每个打印语句前后添加一个打印“---”。但因为我不喜欢重复自己,我会做一个装饰师
def addDashes(fn): # notice it takes a function as an argument
def newFunction(self): # define a new function
print "---"
fn(self) # call the original function
print "---"
return newFunction
# Return the newly defined function - it will "replace" the original
所以现在我可以把我的班级改成
class foo:
@addDashes
def bar(self):
print "hi"
@addDashes
def foobar(self):
print "hi again"
有关装饰器的详细信息,请查看http://www.ibm.com/developerworks/linux/library/l-cpdecor.html
当您需要在decorator中添加自定义参数时,我会添加一个案例,将其传递给最终函数,然后使用它。
装饰师:
def jwt_or_redirect(fn):
@wraps(fn)
def decorator(*args, **kwargs):
...
return fn(*args, **kwargs)
return decorator
def jwt_refresh(fn):
@wraps(fn)
def decorator(*args, **kwargs):
...
new_kwargs = {'refreshed_jwt': 'xxxxx-xxxxxx'}
new_kwargs.update(kwargs)
return fn(*args, **new_kwargs)
return decorator
以及最终功能:
@app.route('/')
@jwt_or_redirect
@jwt_refresh
def home_page(*args, **kwargs):
return kwargs['refreched_jwt']
或者,您可以编写一个工厂函数,该函数返回一个装饰器,该装饰器将装饰函数的返回值包装在传递给工厂函数的标记中。例如:
from functools import wraps
def wrap_in_tag(tag):
def factory(func):
@wraps(func)
def decorator():
return '<%(tag)s>%(rv)s</%(tag)s>' % (
{'tag': tag, 'rv': func()})
return decorator
return factory
这使您能够编写:
@wrap_in_tag('b')
@wrap_in_tag('i')
def say():
return 'hello'
or
makebold = wrap_in_tag('b')
makeitalic = wrap_in_tag('i')
@makebold
@makeitalic
def say():
return 'hello'
就我个人而言,我会用不同的方式来编写装饰器:
from functools import wraps
def wrap_in_tag(tag):
def factory(func):
@wraps(func)
def decorator(val):
return func('<%(tag)s>%(val)s</%(tag)s>' %
{'tag': tag, 'val': val})
return decorator
return factory
这将产生:
@wrap_in_tag('b')
@wrap_in_tag('i')
def say(val):
return val
say('hello')
不要忘了decorator语法是一种简写的构造:
say = wrap_in_tag('b')(wrap_in_tag('i')(say)))