Python-装饰器的进阶 小知识点
⼀. 通⽤装饰器的回顾
开闭原则: 对增加功能开放. 对修改代码封闭
装饰器的作⽤: 在不改变原有代码的基础上给⼀个函数增加功能
通⽤装饰器的写法:
def wrapper(fn):
def inner(*args, **kwargs):
'''在⽬标函数之前做的事情'''
ret = fn(*args, **kwargs)
'''在⽬标函数执⾏之后做的事情'''
return ret
return inner
@wrapper
def target_func():
'''⽬标函数体'''
target_func()
执⾏过程:
1. 程序从上向下, 当执⾏到@wrapper的时候. 把函数作为参数传递给wrapper函数. 得到
inner函数. 重新赋值给target_func
2. 当执⾏到target_func的时候. 我们实际上执⾏的是inner函数. inner函数会先执⾏⽬标
函数之前的代码. 然后再执⾏你的⽬标函数. 执⾏完⽬标函数最后执⾏的是⽬标函数
之后的代码
⼆. 函数的有⽤信息
1. 如何给函数添加注释
def chi(food, drink):
"""
这⾥是函数的注释, 先写⼀下当前这个函数是⼲什么的, ⽐如我这个函数就是⼀个吃
:param :param food: 参数food是什么意思:param :param drink: 参数drink是什么意思
:return :return: 返回的是什么东东
"""
print(food, drink)
return "very good
2. 如何获取到函数的相关信息
def chi(food, drink):
"""
这⾥是函数的注释, 先写⼀下当前这个函数是⼲什么的, ⽐如我这个函数就是⼀个吃
:param :param food: 参数food是什么意思
:param :param drink: 参数drink是什么意思
:return :return: 返回的是什么东东
"""
print(food, drink)
"""
这个可以获取到么
"""
print(chi.__doc__) # 获取函数的⽂档注释
print(chi.__name__) # 获取到函数名称
return "very good"
chi("吃嘛嘛⾹", "我不想吃")
print(chi.__doc__)
print(chi.__name__)
函数名.__name__可以查看函数的名字
函数名.__doc__ 可以查看函数的⽂档注释
接下来. 我们来看⼀看被装饰器装饰之后的函数名 :
# 装饰器: 对传递进来的函数进⾏包装. 可以在⽬标函数之前和之后添加任意的功能.
def wrapper(func):
def inner(*args, **kwargs):
'''在执⾏⽬标函数之前要执⾏的内容'''
ret = func(*args, **kwargs)
'''在执⾏⽬标函数之后要执⾏的内容'''
return ret
return inner
# @wrapper 相当于 target_func = wrapper(target_func) 语法糖
@wrapper
def target_func():
print("我是⽬标函数")# 调⽤⽬标函数
target_func()
print(target_func.__name__) # inner
结果:
inner
我们虽然访问的是target_func函数. 但是实际上执⾏的是inner函数. 这样就会给下游的程
序员带来困惑. 之前不是⼀直执⾏的是target_func么. 为什么突然换成了inner. inner是个什
么⿁?? 为了不让下游程序员有这样的困惑. 我们需要把函数名修改⼀下. 具体修改⽅案
from functools import wraps # 引⼊函数模块 # 装饰器: 对传递进来的函数进⾏包装. 可以在⽬标函数之前和之后添加任意的功能.
def wrapper(func):
@wraps(func) # 使⽤函数原来的名字
def inner(*args, **kwargs):
'''在执⾏⽬标函数之前要执⾏的内容'''
ret = func(*args, **kwargs)
'''在执⾏⽬标函数之后要执⾏的内容'''
return ret
return inner
# @wrapper 相当于 target_func = wrapper(target_func) 语法糖
@wrapper
def target_func():
print("我是⽬标函数")
# 调⽤⽬标函数
target_func()
print(target_func.__name__) # 不再是inner. ⽽是target_func了
@wrapper
def new_target_func():
print("我是另⼀个⽬标函数")
new_target_func()
print(new_target_func.__name__)
PS: *args和**kwargs什么时候打散, 什么时候聚合
1. 接收参数的时候是聚合, 参数声明
2. 传递参数的时候是打散, 给函数传递实参
def wrapper(func):
@wraps(func)
def inner(*args, **kwargs): # 这⾥是聚合
'''在执⾏⽬标函数之前要执⾏的内容'''
ret = func(*args, **kwargs) # 这⾥是打散, 这⾥的作⽤. 其实就是为了保证我可以装饰所有函数⽽准备的
'''在执⾏⽬标函数之后要执⾏的内容'''
return ret
return inner
三. 装饰器传参
现在来这样⼀个场景. 还是昨天的约
from functools import wraps
def wrapper(fn):
@wraps(fn)
def inner(*args, **kwargs):
print("问问⾦⽼板啊, ⾏情怎么样.")
ret = fn(*args, **kwargs)
print("⺾, ⾦⽼板骗我")
return ret
return inner
@wrapper
def yue():
print("约⼀次⼜不会死")
yue()
那么现在如果查的很严. 怎么办呢? 打电话问⾦老板严不严. 那如果整体⻛声都不是那么
紧呢. 是不是就不需要问⾦老板了. 所以. 我们需要⼀个开关来控制是否要询问⾦老板. 这时
我们就需要给装饰器传递⼀个参数. 来通知装饰器要⽤怎么样的⽅式来装饰你的⽬标函数
from functools import wraps
def wrapper_out(flag):
def wrapper(fn):
@wraps(fn)
def inner(*args, **kwargs):
if flag == True: # 查的严啊. 先问问吧
print("问问⾦⽼板啊, ⾏情怎么样.")
ret = fn(*args, **kwargs)
print("⺾, ⾦⽼板骗我")
return ret
else: # 查的不严. 你慌什么
ret = fn(*args, **kwargs)
return ret
return inner
return wrapper
@wrapper_out(False) # 传递True和False来控制装饰器内部的运⾏效果
def yue():
print("约⼀次⼜不会死")
yue()
注意: 咱们之前的写法是@wrapper 其中wrapper是⼀个函数. 那么也就是说. 如果我能让
wrapper这⾥换成个函数就⾏了. wrapper(True)返回的结果是wrapper也是⼀个函数啊. 刚刚
好和前⾯的@组合成⼀个@wrapper. 依然还是原来那个装饰器. 只不过这⾥套了3层. 但你要
能看懂. 其实还是原来那个装饰器@wrapper
执⾏步骤: 先执⾏wrapper(True) 然后再@返回值. 返回值恰好是wrapper. 结果就是
@wrapper
四. 多个装饰器装饰同⼀个函数
先读⼀下这样⼀个代码.
def wrapper1(fn):
def inner(*args, **kwargs):
print("111")
ret = fn(*args, **kwargs)
print("222")
return ret
return inner
def wrapper2(fn):
def inner(*args, **kwargs):
print("333")
ret = fn(*args, **kwargs)
print("444")
return ret
return inner
@wrapper2
@wrapper1
def eat():
print("我想吃⽔果")
eat()
结果:
333
111
我想吃⽔果
222
444
执⾏顺序: ⾸先@wrapper1装饰起来. 然后获取到⼀个新函数是wrapper1中的inner. 然后执
⾏@wrapper2.这个时候. wrapper2装饰的就是wrapper1中的inner了. 所以. 执⾏顺序就像:
第⼆层装饰器前(第⼀层装饰器前(⽬标)第⼀层装饰器后)第⼆层装饰器后. 程序从左到右执⾏
起来. 就是我们看到的结果
- decode : 解码 : 将bytes类型转成字符串
# s = "提前祝大家生日快乐"
# bys = s.encode("UTF-8") # 编码
# print(bys)
# s1 = bys.decode("UTF-8") # 解码
# print(s1) # 把utf-8 转换成GBK的bytes
# bys = b'\xe6\x8f\x90'
# s = bys.decode("utf-8")
# gbk_bys = s.encode("gbk")
# print(gbk_bys)
- enumerate() : 枚举 : 可以直接获取到索引和元素
lst = ["彭于晏", "詹姆斯", "奥特曼", "唐僧"] # for e in lst:
# print(e)
# for i in range(0, len(lst)):
# print(i) # for index, element in enumerate(lst): # enumerate 可以直接获取到索引和元素
# print(index, element) # for e in enumerate(lst):
# print(e)
Python-装饰器的进阶 小知识点的更多相关文章
- Python 装饰器(进阶篇)
装饰器是什么呢? 我们先来打一个比方,我写了一个python的插件,提供给用户使用,但是在使用的过程中我添加了一些功能,可是又不希望用户改变调用的方式,那么该怎么办呢? 这个时候就用到了装饰器.装饰器 ...
- Python装饰器的进阶
带参数的装饰器 示例一:Python自带的装饰器函数 from functools import wraps import time def Time(func1): @wraps(func1) de ...
- (转)python装饰器进阶一
Python装饰器进阶之一 先看例子 网上有很多装饰器的文章,上来说半天也没让人看明白装饰器到底是个什么,究竟有什么用,我们直接来看几个例子. Python递归求斐波那契数列 def fibonacc ...
- 一篇关于Python装饰器的博文
这是一篇关于python装饰器的博文 在学习python的过程中处处受阻,之前的学习中Python的装饰器学习了好几遍也没能真正的弄懂.这一次抓住视频猛啃了一波,就连python大佬讲解装饰器起来也需 ...
- Python装饰器探险
关于python装饰器的理解和用法,推荐廖雪峰老师和这一篇博客以及知乎 以下代码均已手动敲过,看完本篇内容,包你装饰器小成! 装饰器实际上就是为了给某程序增添功能,但该程序已经上线或已经被使用,那么就 ...
- Python装饰器完全解读
1 引言 装饰器(Decorators)可能是Python中最难掌握的概念之一了,也是最具Pythonic特色的技巧,深入理解并应用装饰器,你会更加感慨——人生苦短,我用Python. 2 初步理解装 ...
- python装饰器通俗易懂的解释!
1.python装饰器 刚刚接触python的装饰器,简直懵逼了,直接不懂什么意思啊有木有,自己都忘了走了多少遍Debug,查了多少遍资料,猜有点点开始明白了.总结了一下解释得比较好的,通俗易懂的来说 ...
- Python装饰器由浅入深
装饰器的功能在很多语言中都有,名字也不尽相同,其实它体现的是一种设计模式,强调的是开放封闭原则,更多的用于后期功能升级而不是编写新的代码.装饰器不光能装饰函数,也能装饰其他的对象,比如类,但通常,我们 ...
- Python装饰器与面向切面编程
今天来讨论一下装饰器.装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等.装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数 ...
随机推荐
- Fiddler之iOS手机抓包代理设置
一.前置步骤:官网下载并安装好 二.设置iOS手机代理到windows电脑 1.打开Fiddler,点击上方Tools,进入Options,选择HTTPS,按下图设置 2.fiddler默认监听端口8 ...
- Python开发简介
年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程序,作为ABC语言的一种继承 . 最新的TIOBE排行榜,Python已经占据世界第四名的位置, Python崇尚优美 ...
- PHP导出带有emoji表情的文本到excel文件出问题了
前段时间做了一个导出用户信息(包含微信昵称)到excel文件的功能,一直没问题,今天突然有人反馈说导出来的数据有一些丢失了.我试了一下,发现有些数据导出没问题,有些有问题,某些列出现了空白,数据打印出 ...
- config maven in intellij IDEA
Config maven in IDEA File ->Settings->Build,Execution.Deployment->build Too ...
- 【杂记】docker搭建ELK 集群6.4.0版本 + elasticsearch-head IK分词器与拼音分词器整合
大佬博客地址:https://blog.csdn.net/supermao1013/article/category/8269552 docker elasticsearch 集群启动命令 docke ...
- NFS 共享存储实战
目录 NFS 共享存储实战 一.NFS概述 二.NFS部署 部署NFS客户端backup和web01 统一web.nfs.backup的用户权限 代码部署步骤 三.NFS配置详解 NFS存储小结 四. ...
- Linux常用功能脚本
设置定时任务 crontab -e 1 0 * * * /bin/find /mnt/tomcat/logs/ -mtime +3 -type f -name "*.log" -e ...
- webpack 学习4 使用loader 以及常用的一些loader
webpack本身只支持处理JavaScript,其他的文件,如css img less是不识别的,所以才会有loader这个东西,它就是可以使webpack能够处理其他非js文件的拓展程序 首先我们 ...
- PHP获取用户是否关注公众号。获取微信openid和用户信息
<?php /* * 首先填写授权地址为当前网址 * 将$appid和$secret参数替换成自己公众号对应参数,需要外网可以访问服务器环境测试 */ header("Content- ...
- tp框架连接数据库配置及Model数据模型层
在config.php做数据库连接配置 <?php return array( //'配置项'=>'配置值' 'SHOW_PAGE_TRACE'=>true, /* 数据库设置 */ ...