最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 科技 - 知识百科 - 正文

Python修饰器与functools_html/css

来源:动视网 责编:小采 时间:2020-11-27 16:22:19
文档

Python修饰器与functools_html/css

Python修饰器与functools_html/css_WEB-ITnose:Python 的修饰器是一种语法糖(Syntactic Sugar),也就是说: @decorator@wrapdef func(): pass 是下面语法的一种简写: def func(): passfunc = decorator(wrap(func)) 关于修饰器的两个主要问题: 修饰器用来修饰谁 谁可以作为修饰器
推荐度:
导读Python修饰器与functools_html/css_WEB-ITnose:Python 的修饰器是一种语法糖(Syntactic Sugar),也就是说: @decorator@wrapdef func(): pass 是下面语法的一种简写: def func(): passfunc = decorator(wrap(func)) 关于修饰器的两个主要问题: 修饰器用来修饰谁 谁可以作为修饰器


Python 的修饰器是一种语法糖(Syntactic Sugar),也就是说:

@decorator@wrapdef func(): pass

是下面语法的一种简写:

def func(): passfunc = decorator(wrap(func))

关于修饰器的两个主要问题:

  1. 修饰器用来修饰谁

  2. 谁可以作为修饰器

修饰函数

修饰器最常见的用法是修饰新定义的函数,在 0x0d 上下文管理器中提到上下文管理器主要是为了 更优雅地完成善后工作,而修饰器通常用于扩展函数的行为或属性:

def log(func): def wraper(): print("INFO: Starting {}".format(func.__name__)) func() print("INFO: Finishing {}".format(func.__name__)) return wraper@logdef run(): print("Running run...")run()
INFO: Starting runRunning run...INFO: Finishing run

修饰类

除了修饰函数之外,Python 3.0 之后增加了对新定义类的修饰(PEP 3129),但是对于类别属性的修改可以通过 Metaclasses或继承来实现,而新增加的类别修饰器更多是出于 Jython 以及 IronPython 的考虑,但其语法还是很一致的:

from time import sleep, timedef timer(Cls): def wraper(): s = time() obj = Cls() e = time() print("Cost {:.3f}s to init.".format(e - s)) return obj return wraper@timerclass Obj: def __init__(self): print("Hello") sleep(3) print("Obj")o = Obj()
HelloObjCost 3.005s to init.

类作为修饰器

上面两个例子都是以函数作为修饰器,因为函数才可以被调用(callable) decorator(wrap(func))。除了函数之外,我们也可以定义可被调用的类,只要添加 __call__方法即可:

class HTML(object): """ Baking HTML Tags! """ def __init__(self, tag="p"): print("LOG: Baking Tag <{}>!".format(tag)) self.tag = tag def __call__(self, func): return lambda: "<{0}>{1}".format(self.tag, func(), self.tag) @HTML("html")@HTML("body")@HTML("div")def body(): return "Hello"print(body())
LOG: Baking Tag !LOG: Baking Tag !LOG: Baking Tag !Hello

传递参数

在实际使用过程中,我们可能需要向修饰器传递参数,也有可能需要向被修饰的函数(或类)传递参数。按照语法约定,只要修饰器 @decorator中的 decorator是可调用即可, decorator(123)如果返回一个新的可调用函数,那么也是合理的,上面的 @HTML('html')即是一例,下面再以 flask 的路由修饰器为例说明如何传递参数给修饰器:

RULES = {}def route(rule): def decorator(hand): RULES.update({rule: hand}) return hand return decorator @route("/")def index(): print("Hello world!")def home(): print("Welcome Home!")home = route("/home")(home)index()home()print(RULES)
Hello world!Welcome Home!{'/': , '/home': }

向被修饰的函数传递参数,要看我们的修饰器是如何作用的,如果像上面这个例子一样未执行被修饰函数只是将其原模原样地返回,则不需要任何处理(这就把函数当做普通的值一样看待即可):

@route("/login")def login(user = "user", pwd = "pwd"): print("DB.findOne({{{}, {}}})".format(user, pwd))login("hail", "python")
DB.findOne({hail, python})

如果需要在修饰器内执行,则需要稍微变动一下:

def log(f): def wraper(*args, **kargs): print("INFO: Start Logging") f(*args, **kargs) print("INFO: Finish Logging") return wraper@logdef run(hello = "world"): print("Hello {}".format(hello))run("Python")
INFO: Start LoggingHello PythonINFO: Finish Logging

functools

由于修饰器将函数(或类)进行包装之后重新返回: func = decorator(func),那么有可能改变原本函数(或类)的一些信息,以上面的 HTML修饰器为例:

@HTML("body")def body(): """ return body content """ return "Hello, body!"print(body.__name__)print(body.__doc__)
LOG: Baking Tag !None

因为 body = HTML("body")(body),而 HTML("body").__call__()返回的是一个 lambda函数,因此 body已经被替换成了 lambda,虽然都是可执行的函数,但原来定义的 body中的一些属性,例如 __doc__/ __name__/ __module__都被替换了(在本例中 __module__没变因为都在同一个文件中)。为了解决这一问题 Python 提供了 functools标准库,其中包括了 update_wrapper和 wraps两个方法(源码)。其中 update_wrapper就是用来将原来函数的信息赋值给修饰器中返回的函数:

from functools import update_wrapper"""functools.update_wrapper(wrapper, wrapped[, assigned][, updated])"""class HTML(object): """ Baking HTML Tags! """ def __init__(self, tag="p"): print("LOG: Baking Tag <{}>!".format(tag)) self.tag = tag def __call__(self, func): wraper = lambda: "<{0}>{1}".format(self.tag, func(), self.tag) update_wrapper(wraper, func) return wraper @HTML("body")def body(): """ return body content! """ return "Hello, body!"print(body.__name__)print(body.__doc__)
LOG: Baking Tag !body return body content!

有趣的是 update_wrapper的用法本身就很像是修饰器,因此 functools.wraps就利用 functools.partial(还记得函数式编程中的偏应用吧!)将其变成一个修饰器:

from functools import update_wrapper, partialdef my_wraps(wrapped): return partial(update_wrapper, wrapped=wrapped)def log(func): @my_wraps(func) def wraper(): print("INFO: Starting {}".format(func.__name__)) func() print("INFO: Finishing {}".format(func.__name__)) return wraper@logdef run(): """ Docs' of run """ print("Running run...")print(run.__name__)print(run.__doc__)
run Docs' of run

参考

  1. Python修饰器的函数式编程

文档

Python修饰器与functools_html/css

Python修饰器与functools_html/css_WEB-ITnose:Python 的修饰器是一种语法糖(Syntactic Sugar),也就是说: @decorator@wrapdef func(): pass 是下面语法的一种简写: def func(): passfunc = decorator(wrap(func)) 关于修饰器的两个主要问题: 修饰器用来修饰谁 谁可以作为修饰器
推荐度:
标签: html python css
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top