装饰器进阶

现在,我们已经明白了装饰器的原理。接下来,我们还有很多事情需要搞清楚。比如:装饰带参数的函数、多个装饰器同时装饰一个函数、带参数的装饰器和类装饰器。

装饰带参数函数

def foo(func):  # 接收的参数是一个函数名
def bar(x, y): # 这里需要定义和被装饰函数相同的参数
print("这里是新功能...") # 新功能
func(x, y) # 被装饰函数名和参数都有了,就能执行被装饰函数了
return bar # 定义一个需要两个参数的函数
@foo
def f1(x, y):
print("{}+{}={}".format(x, y, x+y)) # 调用被装饰函数
f1(100, 200)

输出:

这里是新功能...
100+200=300

多个装饰器

def foo1(func):
print("d1") def inner1():
print("inner1")
return "<i>{}</i>".format(func()) return inner1 def foo2(func):
print("d2") def inner2():
print("inner2")
return "<b>{}</b>".format(func()) return inner2 @foo1
@foo2
def f1():
return "Hello Andy" # f1 = foo2(f1) ==> print("d2") ==> f1 = inner2
# f1 = foo1(f1) ==> print("d1") ==> f1 = foo1(inner2) ==> inner1 ret = f1() # 调用f1() ==> inner1() ==> <i>inner2()</i> ==> <i><b>inner1()</b></i> ==> <i><b>Hello Andy</b></i>
print(ret)

带参数装饰器

被装饰的函数可以带参数,装饰器同样也可以带参数。

回头看我们上面写得那些装饰器,它们默认把被装饰的函数当成唯一的参数。但是呢,有时候我们需要为我们的装饰器传递参数,这种情况下应该怎么办呢?

接下来,我们就一步步实现带参数的装饰器:

首先我们来回顾下上面的代码:

def f1(func):  # f1是我们定义的装饰器函数,func是被装饰的函数
def f2(*arg, **kwargs): # *args和**kwargs是被装饰函数的参数
func(*arg, **kwargs)
return f2

从上面的代码,我们发现了什么?

我的装饰器如果有参数的话,没地方写了…怎么办呢?

还是要使用闭包函数!

我们需要知道,函数除了可以嵌套两层,还能嵌套更多层:

# 三层嵌套的函数1
def f1():
def f2():
name = "Andy"
def f3():
print(name)
return f3
return f2

嵌套三层之后的函数调用:

f = f1()  # f --> f2
ff = f() # ff --> f3
ff() # ff() --> f3() --> print(name) --> Andy

注意:在内部函数f3中能够访问到它外层函数f2中定义的变量,当然也可以访问到它最外层函数f1中定义的变量。

# 三层嵌套的函数2
def f1():
name = "Andy"
def f2():
def f3():
print(name)
return f3
return f2

调用:

f = f1()  # f --> f2
ff = f() # ff --> f3
ff() # ff() --> f3() --> print(name) --> Andy

好了,现在我们就可以实现我们的带参数的装饰器函数了:

# 带参数的装饰器需要定义一个三层的嵌套函数
def d(name): # d是新添加的最外层函数,为我们原来的装饰器传递参数,name就是我们要传递的函数
def f1(func): # f1是我们原来的装饰器函数,func是被装饰的函数
def f2(*arg, **kwargs): # f2是内部函数,*args和**kwargs是被装饰函数的参数
print(name) # 使用装饰器函数的参数
func(*arg, **kwargs) # 调用被装饰的函数
return f2
return f1

上面就是一个带参装饰器的代码示例,现在我们来写一个完整的应用:

def d(a=None):  # 定义一个外层函数,给装饰器传参数--role
def foo(func): # foo是我们原来的装饰器函数,func是被装饰的函数
def bar(*args, **kwargs): # args和kwargs是被装饰器函数的参数
# 根据装饰器的参数做一些逻辑判断
if a:
print("欢迎来到{}页面。".format(a))
else:
print("欢迎来到首页。")
# 调用被装饰的函数,接收参数args和kwargs
func(*args, **kwargs)
return bar
return foo @d() # 不给装饰器传参数,使用默认的'None'参数
def index(name):
print("Hello {}.".format(name)) @d("电影") # 给装饰器传一个'电影'参数
def movie(name):
print("Hello {}.".format(name)) if __name__ == '__main__':
index("Andy")
movie("Andy")

输出:

欢迎来到首页。
Hello Andy.
欢迎来到电影页面。
Hello Andy.

类装饰器和装饰类

类装饰器

除了用函数去装饰函数外,我们还可以使用类去装饰函数。

class D(object):
def __init__(self, a=None):
self.a = a
self.mode = "装饰" def __call__(self, *args, **kwargs):
if self.mode == "装饰":
self.func = args[0] # 默认第一个参数是被装饰的函数
self.mode = "调用"
return self
# 当self.mode == "调用"时,执行下面的代码(也就是调用使用类装饰的函数时执行)
if self.a:
print("欢迎来到{}页面。".format(self.a))
else:
print("欢迎来到首页。")
self.func(*args, **kwargs) @D()
def index(name):
print("Hello {}.".format(name)) @D("电影")
def movie(name):
print("Hello {}.".format(name)) if __name__ == '__main__':
index("Andy")
movie("Andy")

装饰类

我们上面所有的例子都是装饰一个函数,返回一个可执行函数。Python中的装饰器除了能装饰函数外,还能装饰类。

可以使用装饰器,来批量修改被装饰类的某些方法:

# 定义一个类装饰器
class D(object):
def __call__(self, cls):
class Inner(cls):
# 重写被装饰类的f方法
def f(self):
print("Hello Andy.")
return Inner @D()
class C(object): # 被装饰的类
# 有一个实例方法
def f(self):
print("Hello world.") if __name__ == '__main__':
c = C()
c.f()
		</div>

Python装饰器进阶的更多相关文章

  1. (转)python装饰器进阶一

    Python装饰器进阶之一 先看例子 网上有很多装饰器的文章,上来说半天也没让人看明白装饰器到底是个什么,究竟有什么用,我们直接来看几个例子. Python递归求斐波那契数列 def fibonacc ...

  2. (转)python装饰器二

    Python装饰器进阶之二 保存被装饰方法的元数据 什么是方法的元数据 举个栗子 def hello(): print('Hello, World.') print(dir(hello)) 结果如下: ...

  3. Python函数--装饰器进阶

    开放封闭原则 1.对扩展是开放的 为什么要对扩展开放呢? 我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改.所以我们必须允许代码扩展.添加新功能. 2.对修改是封 ...

  4. day 12 - 1 装饰器进阶

    装饰器进阶 装饰器的简单回顾 装饰器开发原则:开放封闭原则装饰器的作用:在不改变原函数的调用方式的情况下,在函数的前后添加功能装饰器的本质:闭包函数 装饰器的模式 def wrapper(func): ...

  5. Python—装饰器详解

    装饰器:(语法糖) 本质是函数,它是赋予函数新功能,但是不改变函数的源代码及调用方式   原则: 1.不能修改被装饰函数的源代码 2.不能修改被装饰函数的调用方式 3.函数的返回值也不变 这两点简而言 ...

  6. day4之装饰器进阶、生成器迭代器

    装饰器进阶 带参数的装饰器 # 某一种情况# 500个函数加装饰器, 加完后不想再加这个装饰器, 再过一个季度,又想加上去# 你可以设计你的装饰器,来确认是否执行 # 第一种情况 # 想要500个函数 ...

  7. 五分钟学会Python装饰器,看完面试不再慌

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是Python专题的第12篇文章,我们来看看Python装饰器. 一段囧事 差不多五年前面试的时候,我就领教过它的重要性.那时候我Pyt ...

  8. Python 装饰器填坑指南 | 最常见的报错信息、原因和解决方案

    本文为霍格沃兹测试学院学员学习笔记. Python 装饰器简介 装饰器(Decorator)是 Python 非常实用的一个语法糖功能.装饰器本质是一种返回值也是函数的函数,可以称之为“函数的函数”. ...

  9. 关于python装饰器

    关于python装饰器,不是系统的介绍,只是说一下某些问题 1 首先了解变量作用于非常重要 2 其次要了解闭包 def logger(func): def inner(*args, **kwargs) ...

随机推荐

  1. 内置函数enumerate()

    enumerate是枚举的意思,顾名思义,enumerate()函数用来将一个可迭代序列生成一个enumerate对象,该enumerate对象的每个元素是由可迭代对象的索引编号和对应的元素组成的元祖 ...

  2. haoi2006_受欢迎的牛_Solution

    Brief Solution: 强连通tarjan+压缩点+判断是否除了一个点,其它点都有出度 Detailed Solution: 把牛看成点若一个点b能到达点a,则b认为a受欢迎若所有的点都能到达 ...

  3. jq禁用html标签

    原文:http://www.jb51.net/article/105154.htm 移除或禁用html元素的点击事件可以通过css实现也可以通过js或jQuery实现. 一.CSS方法 .disabl ...

  4. mybatis的面试一对一,一对多,多对多的mapper.xml配置

    使用springboot完成一对一,一对多: https://blog.csdn.net/KingBoyWorld/article/details/78966789 传统的mapper文件中的一对一, ...

  5. 分布式系统登录功能拦截器的实现以及cookie的共享问题(利用cookie实现session在分布式系统的共享)

    当我们的网站采用分布式部署系统时,每个子系统拥有自己独立的session,如果不实现session共享,当用户切换系统访问的时候,会不停的提示登录,这对于用户体验是非常不好的.因此对于多个子系统的的访 ...

  6. CentOS6.7定制化制作ISO

    CentOS6.7定制化制作ISO 以CentOS 6.7-minimal为例. 欢迎大家转载,并保留原文出处.内容若有错误或补充,请联系:szyzln@126.com 本文主要讲解如何在已有官方Ce ...

  7. Access时间日期函数大全

    这里特别推荐WeekdayName() 函数.MonthName() 函数,将日期转换为中文星期名与月份,如"星期一"."五月"一.Date() 函数.Now( ...

  8. JDK环境变量的配置1

    JDK环境变量的配置 ... 1.安装完JDK后配置环境变量  计算机→属性→高级系统设置→高级→环境变量   2.系统变量→新建 JAVA_HOME 变量 .变量值填写jdk的安装目录(我的安装目录 ...

  9. 命令卸载ie11

    管理员运行cmd. 执行命令FORFILES /P %WINDIR%\servicing\Packages /M Microsoft-Windows-InternetExplorer-*11.*.mu ...

  10. Solr记录-solr介绍及配置

    Solr是一个开源搜索平台,用于构建搜索应用程序. 它建立在Lucene(全文搜索引擎)之上. Solr是企业级的,快速的和高度可扩展的. 使用Solr构建的应用程序非常复杂,可提供高性能. 为了在C ...