python 装饰器

Posted catfish1921

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python 装饰器相关的知识,希望对你有一定的参考价值。

今天学brython的时候发现了它的ajax请求太繁琐了。比如:

from browser import document, ajax

url = "http://api.open-notify.org/iss-now.json"
msg = "Position of the International Space Station at {}: {}"

def complete(request):
    import json
    import datetime
    data = json.loads(request.responseText)
    position = data["iss_position"]
    ts = data["timestamp"]
    now = datetime.datetime.fromtimestamp(ts)
    document["zone10"].text = msg.format(now, position)

def click(event):    # 就是这个函数的代码,感觉挺没用的,还要敲好几行……一点不符合python的优雅
    req = ajax.ajax()
    req.open("GET", url, True)
    req.bind("complete", complete)
    document["zone10"].text = "waiting..."
    req.send()

document["button10"].bind("click", click)

这是官方给出的代码,然后我在想怎么将这坨代码搞得精简点。于是我想到了装饰器。鉴于我装饰器基础不是很扎实,但是为了以后敲代码的方便,我打算手撕一个python库来一行代码解决ajax的发送问题。为了解决这个问题,我把装饰器学了一遍(都怪我以前偷懒,觉得搞懂原理也没啥用,然后遇到问题了被迫学一遍)。

写这篇博客先主要理解下装饰器。

函数做装饰器

不含参数的装饰器

代码如下:

def hello(func):
    def world():
        pass
    return world

@hello
def a():
    print("hello world!")

装饰器代码等效于:

hello(a)

再精简点,等效于:

world  # 对,就是这个函数名

所以调用这个函数:

a()   # 等效于调用:hello(a)() -> 再等效于调用 world()

这个应该没问题了。

含参的装饰器

这个就直接把我的那个ajax的例子放出来吧:

from browser import ajax, bind, document
from functools import wraps

def send_ajax(url, method="GET", data=None, sync=True):
    def hello(func):
        @wraps(func)
        def world(*args, **kwargs):
            req = ajax.ajax()
            req.open(method, url, sync)
            req.bind("complete", func)
            if data is None:
                req.send()
            else:
                req.send(data)
        return world
    return hello

然后使用:

from browser import bind, document
from litter_ajax import send_ajax        # 导入自己写的包

url = "http://api.open-notify.org/iss-now.json"
msg = "Position of the International Space Station at {}: {}"

@bind(document[\'button10\'], \'click\')
@send_ajax(url, method="GET", data=None, sync=True)       # 只用多添加一行代码即可!
def complete(request):
    import json
    import datetime
    data = json.loads(request.responseText)
    position = data["iss_position"]
    ts = data["timestamp"]
    now = datetime.datetime.fromtimestamp(ts)
    document["zone10"].text = msg.format(now, position)

不过要注意,ajax要在服务器下才能跨文件执行,可以用brython提供的服务器命令:

py -m http.server

这样就可以了!对了,还有关键的没说:

  1. 如果同时修饰两个装饰器,会先执行最下面的那个装饰器,然后再执行上面的装饰器。
  2. 如果是含参数的装饰器,一般有三层闭包,第一层写所有相关的参数,第二层写函数名,第三层写调用时候传的参数。

好了,可以继续了。

用类做装饰器

不含参数的装饰器

和函数没啥区别,就是多了个__call__函数:

class Hello:
    def __init__(self):
        pass
    
    def __call__(self, func):
        def world():
            pass
        return world

对,和函数没啥区别,知道__call__是干啥的这坨代码就没了。

含参数的装饰器

还是拿我的代码举例子,如下:

class send_ajax:
    def __init__(self, url, method="GET", data=None, sync=True):
        self.url = url
        self.method = method
        self.data = data
        self.sync = sync

    def __call__(self, func):
        @wraps(func)
        def world(*args, **kwargs):
            req = ajax.ajax()
            req.open(self.method, self.url, self.sync)
            req.bind("complete", func)
            if self.data is None:
                req.send()
            else:
                req.send(self.data)
        return world

看懂了函数的代码想必这个代码也好理解。

好了,结束了 ~

以上是关于python 装饰器的主要内容,如果未能解决你的问题,请参考以下文章

[TimLinux] Python 装饰器

python装饰器

python装饰器关键代码

Python装饰器

python之装饰器

python 装饰器