python烧瓶如何将一个动态参数传递给一个装饰器 [英] python flask how to pass a dynamic parameter to a decorator

查看:359
本文介绍了python烧瓶如何将一个动态参数传递给一个装饰器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用python烧瓶框架。我写了一个装饰器,它将需要一个参数,而这个参数将是动态的。

我的装饰器就像下面的那样,会得到一个关键字,并且使用关键的获取数据(key):
def fn_wrapper(f):
@wraps(f):
$ b

 def deco_function(* args,** kwargs):
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,如果一切正常,关键将是这样的



shop_100_style

但是我得到了错误:

  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中,如何将一个动态参数传递给装饰器?



谢谢。

解决方案

如果我们检查全球烧瓶应用程序 flask.g
lockquote

要共享一个请求只对一个函数有效的数据,一个全局变量是不好的足够的,因为它会打破线程环境。 Flask为您提供特殊对象,确保它仅对活动请求有效,并且会为每个请求返回不同的值。


这是通过使用线程本地代理( 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 
$ b $ class ShopAreaAndStyleListAPI(Resource):
@redis_hash_shop_style(key = LocalProxy(lambda:'shop _ {} _ style'.format(g.city .id)))
def get(self):
如果从redis中没有找到,则从mysql查询
pass
flask
或非$ werkzeug
应用程序),我们可以从 LazyProxy > 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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆