关于python decorator找到的一篇比较好的文章
2012-12-06 12:11
507 查看
http://flask.pocoo.org/docs/patterns/viewdecorators/#view-decorators
View Decorators
Python has a really interesting feature called function decorators. Thisallow some really neat things for web applications. Because each view inFlask is a function decorators can be used to inject additionalfunctionality to one or more functions. Theroute()decoratoris the one you probably used already. But there are use casesfor implementing your own decorator. For instance, imagine you have aview that should only be used by people that are logged in to. If a usergoes to the site and is not logged in, they should be
redirected to thelogin page. This is a good example of a use case where a decorator is anexcellent solution.
Login Required Decorator
So let’s implement such a decorator. A decorator is a function thatreturns a function. Pretty simple actually. The only thing you have tokeep in mind when implementing something like this is to update the__name__,__module__ andsome other attributes of a function. This isoften forgotten, but you don’t have to do that by hand, there is afunction for that that is used like a decorator (functools.wraps()).
This example assumes that the login page is called
'login' and thatthe current user is stored as
g.user and None if there is no-onelogged in:
from functools import wraps from flask import g, request, redirect, url_for def login_required(f): @wraps(f) def decorated_function(*args, **kwargs): if g.user is None: return redirect(url_for('login', next=request.url)) return f(*args, **kwargs) return decorated_function
So how would you use that decorator now? Apply it as innermost decoratorto a view function. When applying further decorators, always rememberthat theroute()
decorator is the outermost:
@app.route('/secret_page') @login_required def secret_page(): pass
Caching Decorator
Imagine you have a view function that does an expensive calculation andbecause of that you would like to cache the generated results for acertain amount of time. A decorator would be nice for that. We’reassuming you have set up a cache like mentioned inCaching.Here an example cache function. It generates the cache key from aspecific prefix (actually a format string) and the current path of therequest. Notice that we are using a function that first creates thedecorator that then decorates the function. Sounds awful?
Unfortunatelyit is a little bit more complex, but the code should still bestraightforward to read.
The decorated function will then work as follows
get the unique cache key for the current request base on the currentpath.
get the value for that key from the cache. If the cache returnedsomething we will return that value.
otherwise the original function is called and the return value isstored in the cache for the timeout provided (by default 5 minutes).
Here the code:
from functools import wraps from flask import request def cached(timeout=5 * 60, key='view/%s'): def decorator(f): @wraps(f) def decorated_function(*args, **kwargs): cache_key = key % request.path rv = cache.get(cache_key) if rv is not None: return rv rv = f(*args, **kwargs) cache.set(cache_key, rv, timeout=timeout) return rv return decorated_function return decorator
Notice that this assumes an instantiated cache object is available, seeCaching for more information.
Templating Decorator
A common pattern invented by the TurboGears guys a while back is atemplating decorator. The idea of that decorator is that you return adictionary with the values passed to the template from the view functionand the template is automatically rendered. Withthat, the followingthree examples do exactly the same:
@app.route('/') def index(): return render_template('index.html', value=42) @app.route('/') @templated('index.html') def index(): return dict(value=42) @app.route('/') @templated() def index(): return dict(value=42)
As you can see, if no template name is provided it will use the endpointof the URL map with dots converted to slashes +'.html'. Otherwisethe provided template name is used. When the decorated function
returns,the dictionary returned is passed to the template rendering function. IfNone is returned, an empty dictionary is assumed, if something else thana dictionary is returned we return it from the function unchanged. Thatway you can still use
the redirect function or return simple strings.
Here the code for that decorator:
from functools import wraps from flask import request def templated(template=None): def decorator(f): @wraps(f) def decorated_function(*args, **kwargs): template_name = template if template_name is None: template_name = request.endpoint \ .replace('.', '/') + '.html' ctx = f(*args, **kwargs) if ctx is None: ctx = {} elif not isinstance(ctx, dict): return ctx return render_template(template_name, **ctx) return decorated_function return decorator
Endpoint Decorator
When you want to use the werkzeug routing system for more flexibility youneed to map the endpoint as defined in theRuletoa view function. This is possible with this decorator. For example:
from flask import Flask from werkzeug.routing import Rule app = Flask(__name__) app.url_map.add(Rule('/', endpoint='index')) @app.endpoint('index') def my_index(): return "Hello world"
相关文章推荐
- Android 一篇比较好的关于ScaleType的说明的文章
- python 对一篇文章,按逗号和句号分成一句一句的,然后在这篇文章中找到与某个句子类似的句子(包含相同的词)
- 无意中找到的一篇关于面试的文章,感觉写的很好!
- 无意中找到的一篇关于面试的文章,感觉写的很好!
- 找到的一篇 关于python 用来生成代码的
- 转载一篇优秀的关于python的字典的文章
- 看了一篇比较好的关于正则表达式的文章
- 一篇写的比较好的关于scala中trait特性的文章
- Python性能鸡汤——新出的一篇关于Python高效编程的文章
- python 对一篇文章,按句号分成一句一句的,然后在这篇文章中找到与某个句子类似的句子(包含相同的词)
- 关于python中文乱码很好的一篇文章
- 看到的一篇讲js比较好的文章,关于function
- 又一篇关于windows消息队列比较好的文章
- 一篇关于python对文件操作讲解的文章
- 关于ASIHttpRequest总结的比较好的一篇文章
- 一篇关于正则表达式讲得比较好的文章
- 找到一篇关于 Oracle 全文检索实践 的文章
- 一篇关于mysql比较好的文章
- 找了许久,终于找到一篇关于GStreamer架构的说的比较详细和底层的文章
- python 对一篇文章,按逗号分成一句一句的,然后在这篇文章中找到与某个句子类似的句子(包含相同的词)