python烧瓶如何将一个动态参数传递给一个装饰器 [英] python flask how to pass a dynamic parameter to a decorator
问题描述
我的装饰器就像下面的那样,会得到一个关键字,并且使用关键的获取数据(key):
def fn_wrapper(f):
@wraps(f):
$ b
data = redis_hash(key)
返回数据
返回装饰函数
返回fn_wrapper
我有一个类来使用这个decorater,像这样的代码
< $ p $ class $ shop $ {$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ):
#如果从redis中没有找到,则从mysql查询
pass
正如你所看到的,我的装饰器需要一个名为 key
的参数,并且像这样传递这个键
@redis_hash_shop_style(KE y ='shop _ {} _ style'.format(g.city.id))
g.city.id
将获得城市的ID,如果一切正常,关键将是这样的
但是我得到了错误: 我很困惑,在flask中,如何将一个动态参数传递给装饰器? 谢谢。 如果我们检查全球烧瓶应用程序, 要共享一个请求只对一个函数有效的数据,一个全局变量是不好的足够的,因为它会打破线程环境。 Flask为您提供特殊对象,确保它仅对活动请求有效,并且会为每个请求返回不同的值。 这是通过使用线程本地代理( 我们可以很容易地通过使用一个懒代理来延迟访问 shop_100_style
应用程序),我们可以从 LazyProxy >
$ c $
class ShopAreaAndStyleListAPI资源):
在ShopAreaAndStyleListAPI
@redis_hash_shop_style(key ='shop_ {} _ style'.format(g.city.id))$ b的文件xx.py
$ b文件/Users/xx/.virtualenvs/yy/lib/python2.7/site-packages/werkzeug/local.py,第347行,在__getattr__
中返回getattr(self._get_current_object (),name)
文件/Users/xx/.virtualenvs/yy/lib/python2.7/site-packages/werkzeug/local.py,行306,在_get_current_object
中返回self。 __local()
文件/Users/xx/.virtualenvs/yy/lib/python2.7/site-packages/flask/globals.py,第44行,在_lookup_app_object
中引发RuntimeError(_app_ctx_err_msg)
RuntimeError:在应用程序上下文之外工作。
这通常意味着您尝试使用
所需的功能来以某种方式与当前应用程序对象进行交互。
为了解决这个问题,用app.app_context()设置了一个应用程序上下文。
请参阅文档以获取更多信息。
flask.g $ c $它说:
或非$
lockquote
flask / globals.py
):
<$
$ b $另外我们应该记住的一点是,Python在执行编译阶段期间,在任何请求之外或者在 flask
应用程序之外执行装饰器的第一遍。这意味着 key
参数被赋值为'shop _ {} _ style'.format(g.city.id)
当你的应用程序启动的时候(当你的类被解析/装饰时),在 flask
请求上下文之外
flask.g
,它只在使用时通过回调函数获取值。我们使用已经与 flask
捆绑在一起的那个, werkzeug.local.LocalProxy
:
from werkzeug.local import LocalProxy
$ p $一般而言(对于非
$ b $ class ShopAreaAndStyleListAPI(Resource):
@redis_hash_shop_style(key = LocalProxy(lambda:'shop _ {} _ style'.format(g.city .id)))
def get(self):
如果从redis中没有找到,则从mysql查询
pass
ProxyTypes
包。
与此无关,您还需要修正 redis_hash_shop_style
装饰器不仅可以从 redis
中获取,还可以更新(或创建)值如果陈旧(或不存在),通过在适当的时候调用包装的 f()
来完成。
I am using python flask framework. I write a decorator which will be need a parameter, and this parameter will be dynamic.
my decorator like below, will be get a key ,and using the key fetch data from redis.
def redis_hash_shop_style(key):
def fn_wrapper(f):
@wraps(f)
def decorated_function(*args, **kwargs):
data = redis_hash(key)
return data
return decorated_function
return fn_wrapper
and I have a class to using this decorater, code like this
class ShopAreaAndStyleListAPI(Resource):
@redis_hash_shop_style(key='shop_{}_style'.format(g.city.id))
def get(self):
# if not found from redis, query from mysql
pass
As you see, my decorator need a parameter named key
, and I pass the key like this
@redis_hash_shop_style(key='shop_{}_style'.format(g.city.id))
g.city.id
will be get the city's id, if everything is ok, the key will be like this
shop_100_style
but I got the error:
class ShopAreaAndStyleListAPI(Resource):
File "xx.py", line 659, in ShopAreaAndStyleListAPI
@redis_hash_shop_style(key='shop_{}_style'.format(g.city.id))
File "/Users/xx/.virtualenvs/yy/lib/python2.7/site-packages/werkzeug/local.py", line 347, in __getattr__
return getattr(self._get_current_object(), name)
File "/Users/xx/.virtualenvs/yy/lib/python2.7/site-packages/werkzeug/local.py", line 306, in _get_current_object
return self.__local()
File "/Users/xx/.virtualenvs/yy/lib/python2.7/site-packages/flask/globals.py", line 44, in _lookup_app_object
raise RuntimeError(_app_ctx_err_msg)
RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that
needed to interface with the current application object in a way.
To solve this set up an application context with app.app_context().
See the documentation for more information.
I am quite confused , in flask, how to pass a dynamic parameter to a decorator?
Thanks.
If we check the docs for flask application global, flask.g
, it says:
To share data that is valid for one request only from one function to another, a global variable is not good enough because it would break in threaded environments. Flask provides you with a special object that ensures it is only valid for the active request and that will return different values for each request.
This is achieved by using a thread-local proxy (in flask/globals.py
):
g = LocalProxy(partial(_lookup_app_object, 'g'))
The other thing we should keep in mind is that Python is executing the first pass of our decorator during the "compile" phase, outside of any request, or flask
application. That means key
argument get assigned a value of 'shop_{}_style'.format(g.city.id)
when your application starts (when your class is being parsed/decorated), outside of flask
request context.
But we can easily delay accessing to flask.g
by using a lazy proxy, which fetches the value only when used, via callback function. Let's use the one already bundled with flask
, the werkzeug.local.LocalProxy
:
from werkzeug.local import LocalProxy
class ShopAreaAndStyleListAPI(Resource):
@redis_hash_shop_style(key=LocalProxy(lambda: 'shop_{}_style'.format(g.city.id)))
def get(self):
# if not found from redis, query from mysql
pass
In general (for non-flask
or non-werkzeug
apps), we can use a similar LazyProxy
from the ProxyTypes
package.
Unrelated to this, you'll also want to fix your redis_hash_shop_style
decorator to not only fetch from redis
, but to also update (or create) the value if stale (or non-existing), by calling the wrapped f()
when appropriate.
这篇关于python烧瓶如何将一个动态参数传递给一个装饰器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!