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
这样就可以了!对了,还有关键的没说:
- 如果同时修饰两个装饰器,会先执行最下面的那个装饰器,然后再执行上面的装饰器。
- 如果是含参数的装饰器,一般有三层闭包,第一层写所有相关的参数,第二层写函数名,第三层写调用时候传的参数。
好了,可以继续了。
用类做装饰器
不含参数的装饰器
和函数没啥区别,就是多了个__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 装饰器的主要内容,如果未能解决你的问题,请参考以下文章