一、为什么要有有参装饰器?

来看之前的无参装饰器

# 无参装饰器
def outter(func):
def wrapper(*args,**kwargs):
start = time.time()
res = func(*args,**kwargs) # 我们需要一个变量接受函数的返回值
end = time.time()
print("run time is %s" % (end - start))
return res # 我们装饰器的核心是wrapper函数,只需要在wrapper函数中提供返回值即可
return wrapper @outter # @+装饰器名称,可以快速完成 pint1 = outter(print1)的函数赋值
def print1(name):
print(name)
time.sleep(1)
return 111

可以看到,我们从outter()和wrapper()向内层函数进行了传参,outter函数传入的是我们所要修饰的函数对象,wrapper则是将参数原封不动的传给了修饰的函数对象,如果现在有个新的需求:

  • 设计一个装饰器,为函数增加认证功能,其中登陆的认证来源有多个(file、mysql)

首先看一下无参装饰器能否实现:

# 认证功能装饰器
def outter(func):
def wrapper(*args,**kwargs):
name = input("请输入用户名>>>")
pwd = input("请输入密码>>>")
if mode == "1": # 需要通过mode进行判断信息来源,但是没有参数传入
if name == "zhangda" and pwd == "123":
print("登陆成功!")
res1 = func(*args,**kwargs)
return res1
else:
print("用户名或者密码错误")
elif mode == "2": #需要通过mode进行判断信息来源,但是没有参数传入
         print("认证来源:mysql")
     else:
         print("未知来源")
return wrapper

我们需要传入一个mode参数进行判断,但是wrapper()需要给func()原样传入参数,所以不能添加mode,外层的outter()可以为mode传参,但是由于python语法糖限制,里面除了func外,不能添加其他的参数,那这个mode参数怎么传入呢?

我们可以在最外层函数进行传入

# 认证功能装饰器
def outter(func):
mode = "file"
def wrapper(*args,**kwargs):
name = input("请输入用户名>>>")
pwd = input("请输入密码>>>")
if mode == "1":
if name == "zhangda" and pwd == "123":
print("登陆成功!")
res1 = func(*args,**kwargs)
return res1
else:
print("用户名或者密码错误")
elif mode == "2":
print("认证来源:mysql")
else:
print("未知来源")
return wrapper @outter
def f1():
print("hhhhh")

但是这样每次使用装饰器都需要修改,并且不能同时满足多个信息来源需求,回想之前给函数传参的两种方法,既然直接传参行不通,我们想到了利用闭包函数特性,再包一层函数,这就是有参装饰器

def outter2(mode="file"):
def outter(func):
def wrapper(*args,**kwargs):
name = input("Username:").strip()
pwd = input("Password:").strip() if mode == "file":
if name == "egon" and pwd == "123":
print("登陆成功!")
res = func(*args,**kwargs)
return res
else:
print("登陆失败!")
elif mode == "mysql":
print("基于mysql认证!")
else:
print("未知来源认证!")
return wrapper
return outter @outter2("mysql")
def index(name):
print("{}".format(name)) index("hhhhhh")

在这里将之前的装饰器outter看做一个整体,对他进行装饰,并且最外层函数可以传入任意参数的,有参装饰的语法糖:@函数名(参数1,参数2......)

二、装饰器wraps

我们知道,装饰器其实就是定义了一个闭包函数,包含了原来的函数与功能并且添加新功能,最后通过函数对象赋值实现了全局调用,但是函数内存地址已经改变,只是名称看着一样

def outter(func):
def wrapper(*args,**kwargs):
"""wrapper注释"""
print("11111")
res = func(*args,**kwargs)
return res
return wrapper @outter
def index():
"""index注释"""
print("2222") print(index.__name__) # 打印函数的名称
print(index.__doc__) # 打印函数的注释
print(index) # 打印函数内存地址

运行结果如下:

index只是披着index外衣的wrapper函数,他的本质其实是wrapper,这不会影响函数的原始使用,但是如果有需求,希望这些属性看着不变呢?

def outter(func):
def wrapper(*args,**kwargs):
"""wrapper注释"""
print("11111")
res = func(*args,**kwargs)
return res
wrapper.__name__ = func.__name__
wrapper.__doc__ = func.__doc__
return wrapper @outter
def index():
"""index注释"""
print("2222") print(index.__name__) # 打印函数的名称
print(index.__doc__) # 打印函数的注释
print(index) # 打印函数内存地址

我们可以通过将wrapper的名称等信息重新复制,将原函数的信息赋值给wrapper即可:

其实python内置了一个库functools,提供了装饰器实现这一功能,用法如下:

from functools import wraps

def outter(func):
@wraps(func)
def wrapper(*args,**kwargs):
"""wrapper注释"""
print("11111")
res = func(*args,**kwargs)
return res
# wrapper.__name__ = func.__name__
# wrapper.__doc__ = func.__doc__
return wrapper @outter
def index():
"""index注释"""
print("2222") print(index.__name__) # 打印函数的名称
print(index.__doc__) # 打印函数的注释
print(index) # 打印函数内存地址

三、总结

装饰器模板

  • 无参装饰器
def outter(func):
def wrapper(*args,**kwargs):
res = func(*args,**kwargs)
return res
return wrapper
  • 有参修饰器
def outter2(x):
def outter(func):
def wrapper(*args,**kwargs):
print(x)
res = func(*args,**kwargs)
return res
return wrapper
return outter @outter2("1")
def f1():
print("2")

python函数之有参装饰器的更多相关文章

  1. Python函数07/有参装饰器/多个装饰器装饰一个函数

    Python函数07/有参装饰器/多个装饰器装饰一个函数 目录 Python函数07/有参装饰器/多个装饰器装饰一个函数 内容大纲 1.有参装饰器 2.多个装饰器装饰一个函数 3.今日总结 3.今日练 ...

  2. Python 函数修饰符(装饰器)的使用

     Python 函数修饰符(装饰器)的使用 1.  修饰符的来源修饰符是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等. 修饰符是解决这类问题的绝佳设计, ...

  3. python学习Day14 带参装饰器、可迭代对象、迭代器对象、for 迭代器工作原理、枚举对象、生成器

    复习 函数的嵌套定义:在函数内部定义另一个函数 闭包:被嵌套的函数 -- 1.外层通过形参给内层函数传参 -- 2.返回内部函数对象---->  延迟执行, 开放封闭原则: 功能可以拓展,但源代 ...

  4. python 函数名 、闭包 装饰器 day13

    1,函数名的使用. 函数名是函数的名字,本质就是变量,特殊的变量.函数名()加括号就是执行此函数. 1,单独打印函数名就是此函数的内存地址. def func1(): print(555) print ...

  5. 第十七篇 Python函数之闭包与装饰器

    一. 装饰器 装饰器:可以拆解来看,器本质就是函数,装饰就是修饰的意思,所以装饰器的功能就是为其他函数添加附加功能. 装饰器的两个原则: 1. 不修改被修饰函数的源代码 2. 不修改被修饰函数的调用方 ...

  6. python函数之闭包函数与无参装饰器

    一.global与nonlocal #global x = 1 def f1(): global x # 声明此处是全部变量x x = 2 print(x) f1() # 调用f1后,修改了全局变量x ...

  7. python函数与模块(装饰器,文件处理,迭代器等)

    os模块 os.system('命令') 利用python调用系统命令,命令可以是以列表或者元组内的元素形式* res import os res=os.system('ipconfig') prin ...

  8. python中的无参装饰器和有参装饰器

    python中的无参装饰器和有参装饰器 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 装饰器特点: 1>.开放封闭原则,即对扩展是开放的,对修改时封闭的: 2>.装饰器 ...

  9. python函数超时,用装饰器解决 func_timeout

    https://zhuanlan.zhihu.com/p/39743129 https://www.jianshu.com/p/a7fc98c7af4d https://ixyzero.com/blo ...

随机推荐

  1. CSS Grid Layout In Action

    CSS Grid Layout In Action CSS 异形网格布局实战 refs https://static-nginx-online.fbcontent.cn/tutor/tutor-ybc ...

  2. learning 2018

    learning 2018 https://scotch.io/courses https://laod.cn/hosts/ipv6-dns.html xgqfrms 2012-2020 www.cn ...

  3. Objective C & Swift & iOS & App

    Objective C & Swift & iOS & App https://www.runoob.com/ios/ios-objective-c.html https:// ...

  4. 没想到即将上线的NGK生态应用这么厉害?!

    话说这即将上线的NGK公链可不是闹着玩的,这条公链的蛰伏时间长达两年,恐怕这个准备时间,连最初的区块链1.0时代的项目都无法比拟,现在的话那都差太远了. 编程一段代码并不难,难的是耐得住赚快钱的心.人 ...

  5. BGV上线两天价格超过880美金,下一个YFI已到来!

    BGV自上线以来就备受币圈关注,众多投资者纷纷表示看好BGV.BGV也不负众望,在上线交易所第二天,价格就迎来了暴涨,最高价格为888.88美金,超越了当前以太坊的价值.而这也迎来了币圈众多投资者的一 ...

  6. VOR/DME程序进近、复飞保护区的绘制

    今天尝试画一个典型的VOR/DME进近程序保护区. 读图 某机场VOR/DME进近程序平面图部分如下图所示:   该程序剖面图部分如下图所示:   分析 该机场采用了偏置导航台布局(导航台在机场内), ...

  7. 亿级流量客户端缓存之Http缓存与本地缓存对比

    客户端缓存分为Http缓存和本地缓存,使用缓存好处很多,例如减少相同数据的重复传输,节省网络带宽资源缓解网络瓶颈,降低了对原始服务器的要求,避免出现过载,这样服务器可以更快响应其他的请求 Http缓存 ...

  8. Java并发之CompletionService详解

    CompletionService是什么? 它是JUC包中的一个接口类,默认实现类只有一个ExecutorCompletionService. CompletionService干什么的? 它将异步任 ...

  9. java与freemarker遍历map

    一.java遍历MAP /** * 1.把key放到一个集合里,遍历key值同时根据key得到值 (推荐) */ Set set =map.keySet(); Iterator it=set.iter ...

  10. Numpy初体验

    目录 Numpy 一.简介 1.安装 2.特殊的导包 二.ndarray-多维数组对象 1.创建ndarray数组 1.1 array 1.2 arange 1.3 linspace 1.4 zero ...