我如何在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的所有函数之间共享:
def counter(func):
def wrapped(*args, **kws):
print 'Called #%i' % wrapped.count
wrapped.count += 1
return func(*args, **kws)
wrapped.count = 0
return wrapped
这样,您的装饰器可以重复用于不同的函数(或用于多次装饰同一个函数:func_counter1=counter(func);func_counter2=counter(func)),并且计数器变量将对每个变量保持私有。
其他回答
#decorator.py
def makeHtmlTag(tag, *args, **kwds):
def real_decorator(fn):
css_class = " class='{0}'".format(kwds["css_class"]) \
if "css_class" in kwds else ""
def wrapped(*args, **kwds):
return "<"+tag+css_class+">" + fn(*args, **kwds) + "</"+tag+">"
return wrapped
# return decorator dont call it
return real_decorator
@makeHtmlTag(tag="b", css_class="bold_css")
@makeHtmlTag(tag="i", css_class="italic_css")
def hello():
return "hello world"
print hello()
也可以在类中编写decorator
#class.py
class makeHtmlTagClass(object):
def __init__(self, tag, css_class=""):
self._tag = tag
self._css_class = " class='{0}'".format(css_class) \
if css_class != "" else ""
def __call__(self, fn):
def wrapped(*args, **kwargs):
return "<" + self._tag + self._css_class+">" \
+ fn(*args, **kwargs) + "</" + self._tag + ">"
return wrapped
@makeHtmlTagClass(tag="b", css_class="bold_css")
@makeHtmlTagClass(tag="i", css_class="italic_css")
def hello(name):
return "Hello, {}".format(name)
print hello("Your name")
考虑下面的修饰符,注意我们将wrapper()函数作为对象返回
def make_bold(func):
def wrapper():
return '<b>'+func()+'</b>'
return wrapper
所以这个
@make_bold
def say():
return "Hello"
计算结果为
x = make_bold(say)
注意,x不是say(),而是在内部调用say(()的包装器对象。这就是装饰师的工作原理。它总是返回调用实际函数的包装器对象。如果链接此
@make_italic
@make_bold
def say():
return "Hello"
转换为此
x = make_bold(say)
y = make_italic(x)
以下是完整的代码
def make_italic(func):
def wrapper():
return '<i>'+func()+'</i>'
return wrapper
def make_bold(func):
def wrapper():
return '<b>'+func()+'</b>'
return wrapper
@make_italic
@make_bold
def say():
return "Hello"
if __name__ == '__main__':
# x = make_bold(say) When you wrap say with make_bold decorator
# y = make_italic(x) When you also add make_italic as part of chaining
# print(y())
print(say())
上述代码将返回
<i><b>Hello</b></i>
希望这有帮助
当您需要在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']
用于绘制图像的嵌套装饰器的又一示例:
import matplotlib.pylab as plt
def remove_axis(func):
def inner(img, alpha):
plt.axis('off')
func(img, alpha)
return inner
def plot_gray(func):
def inner(img, alpha):
plt.gray()
func(img, alpha)
return inner
@remove_axis
@plot_gray
def plot_image(img, alpha):
plt.imshow(img, alpha=alpha)
plt.show()
现在,让我们先使用嵌套的装饰器显示一个没有轴标签的彩色图像:
plot_image(plt.imread('lena_color.jpg'), 0.4)
接下来,让我们使用嵌套的装饰器remove_axis和plot_gray显示一个没有轴标签的灰度图像(我们需要cmap='gray',否则默认的颜色映射是viridis,因此除非明确指定,否则默认情况下灰度图像不会以黑白色显示)
plot_image(plt.imread('lena_bw.jpg'), 0.8)
上述函数调用缩减为以下嵌套调用
remove_axis(plot_gray(plot_image))(img, alpha)
下面有make_bold()和make_italic():
def make_bold(func):
def core(*args, **kwargs):
result = func(*args, **kwargs)
return "<b>" + result + "</b>"
return core
def make_italic(func):
def core(*args, **kwargs):
result = func(*args, **kwargs)
return "<i>" + result + "</i>"
return core
您可以使用say()将它们用作装饰器,如下所示:
@make_bold
@make_italic
def say():
return "Hello"
print(say())
输出:
<b><i>Hello</i></b>
当然,您可以直接使用make_bold()和make_italic()而不使用修饰符,如下所示:
def say():
return "Hello"
f1 = make_italic(say)
f2 = make_bold(f1)
result = f2()
print(result)
简而言之:
def say():
return "Hello"
result = make_bold(make_italic(say))()
print(result)
输出:
<b><i>Hello</i></b>