Python3 函数进阶1
闭包函数
什么是闭包函数
闭包函数本质上就是函数嵌套和高阶函数
闭包函数的满足条件:
- 必须嵌套函数
- 内嵌函数必须引用外部函数的变量
- 外部函数必须返回内嵌函数的函数对象(函数名)
# outer 是一个闭包函数
def outer():
x = 1
def inner():
print(X) # 内嵌函数引用了外部函数里的变量
return inner # 外部函数返回内嵌函数的函数对象
f1 = outer()
f1()
闭包函数的作用
闭包函数不仅返回了内嵌函数的函数对象, 还在其身上包裹了一层(外部函数)的局部作用域. 这使得, 无论该函数对象在何处被调用, 都优先使用包裹在自己身上的这层作用域.
# 常规函数
import requests
def get(url):
response = requests.get(url)
print(f'done:{url})
# 如果后续要多次调用get函数爬取同一网站, 则每次都要输入一次网址
get('https://www.python.org')
get('https://www.python.org')
get('https://www.python.org')
# 使用默认形参也只能解决一个网站
get('https://www.cnblogs.com/bigb/')
get('https://www.cnblogs.com/bigb/')
get('https://www.cnblogs.com/bigb/')
我们可以用闭包函数解决上述问题
# 闭包函数
import requests
# url是外部函数outer的形参, 可以把其看成函数outer局部作用域中的变量
def outer(url):
def get():
response = requests.get(url)
print(f'done:{}')
return get
# 在外部函数空间作用域中存在 url = 'https://www.python.org'这个变量, 内部函数可以永久引用
python = outer('https://www.python.org')
python() # get()
python()
python()
装饰器
什么是装饰器
装饰器本质上就是一个闭包函数, 为被装饰对象添加额外功能
装饰器的实现必须遵循两大原则:
- 不修改被装饰对象源代码
- 不修改被装饰对象的调用方式
无参装饰器
下面我们就用装饰器给既定函数f1增加计时功能
import time
def f1():
'''被装饰函数'''
print('this is f1')
time.sleep(1) # 程序休眠1秒
# 定义time_count装饰器函数, func是形参名, 用来接收函数对象
def time_count(func):
'''装饰器函数'''
# wrapper是辅助函数
def wrapper():
start = time.time()
func() # 使用函数对象调用函数
end = time.time()
print(f'程序耗费时长为: {end - start}')
return wrapper
f1 = time_count(f1) # wrapper
f1() # wrapper()
'''
this is f1
程序耗费时长为: 1.0000574588775635
'''
如果f1是个有参函数我们该怎样通过装饰器传入参数呢?
由上述例子我们知道, f1() = wrapper(), 因此我们给wrapper传参即可
import time
def f1(a):
'''被装饰函数'''
print('this is f1, 参数:', a)
time.sleep(1) # 程序休眠1秒
# 定义time_count装饰器函数, func是形参名, 用来接收函数对象
def time_count(func):
'''装饰器函数'''
# wrapper是辅助函数
def wrapper(*args,**kwargs):
start = time.time()
func(*args,**kwargs) # 使用函数对象调用函数
end = time.time()
print(f'程序耗费时长为: {end - start}')
return wrapper
f1 = time_count(f1) # wrapper
f1(1) # wrapper()
'''
this is f1, 参数: 1
程序耗费时长为: 1.0000572204589844
'''
如果函数f1有返回值我们如何通过装饰器实现呢?
由于f1() = wrapper(), 因此f1 的返回值就是wrapper的返回值
import time
def f1(a):
'''被装饰函数'''
print('this is f1, 参数:', a)
time.sleep(1) # 程序休眠1秒
return a
# 定义time_count装饰器函数, func是形参名, 用来接收函数对象
def time_count(func):
'''装饰器函数'''
# wrapper是辅助函数
def wrapper(*args,**kwargs):
start = time.time()
res = func(*args,**kwargs) # 使用函数对象调用函数
end = time.time()
print(f'程序耗费时长为: {end - start}')
return res
return wrapper
f1 = time_count(f1) # wrapper
res = f1(1)
print(res)
'''
this is f1, 参数: 1
程序耗费时长为: 1.0000569820404053
1
'''
还是不理解装饰器吗? 那就记住装饰器的模板吧!
def deco(func):
def wrapper(*args,**kwargs):
# 添加功能
res = func(*args, **kwargs)
# 添加功能
return res
return wrapper
装饰器语法糖:
就是在被装饰函数上面单独写上@装饰器名
, 它实现的功能是f1 = time_count(f1)
@time_count
def f1(a):
'''被装饰函数'''
print('this is f1, 参数:', a)
time.sleep(1) # 程序休眠1秒
return a
res = f1(1)
print(res)
'''
this is f1, 参数: 1
程序耗费时长为: 1.0000569820404053
1
'''
有参装饰器
我们现在写一个登陆功能的装饰器
# 登陆装饰器
username_list = []
def login(func):
def wrapper(*args, **kwargs):
if username_list:
print('请勿重复登陆')
res = func(*args, **kwargs)
return res
username_inp = input('请输入用户名: ')
pwd_inp = input('请输入密码: ')
# 从user_info读取用户信息
with open('user_info', 'r', encoding='utf-8') as fr:
for user_info in fr:
name, pwd = user_info.strip().split(':')
if name == username_inp and pwd == pwd_inp:
print('登录成功')
username_list.append(username_inp)
res = func(*args, **kwargs) # 先调用 再返回
return res
else:
print('用户名密码错误')
res = func(*args, **kwargs)
return res
return wrapper
上面我只实现了从user_info里面读取用户密码信息进行判断.
现在我们想实现管理员登陆则从admin_info里面读取信息, 用户登陆则从user_info里面读取信息, 该怎么办呢?
username_list = []
def sanceng(role):
def login(func):
def wrapper(*args, **kwargs):
if username_list:
print('请勿重复登陆')
res = func(*args, **kwargs)
return res
username_inp = input('请输入用户名: ')
pwd_inp = input('请输入密码: ')
# 从{role}_info读取用户信息
with open(f'{role}_info', 'r', encoding='utf-8') as fr:
for user_info in fr:
name, pwd = user_info.strip().split(':')
if name == username_inp and pwd == pwd_inp:
print('登录成功')
username_list.append(username_inp)
res = func(*args, **kwargs) # 先调用 再返回
return res
else:
print('用户名密码错误')
return wrapper
return login
# 那我们在装饰 被装饰对象 时就要输入一个参数
@sanceng(admin)
def f1():
pass
Python3 函数进阶1的更多相关文章
- 5 Python3 函数进阶&迭代器与生成器
1.函数进阶 1.1.名称空间 又名name space, 顾名思义就是存放名字的地方,存什么名字呢?举例说明,若变量x=1,1存放于内存中,那名字x存放在哪里呢?名称空间正是存放名字x与1绑定关系的 ...
- Python3 函数进阶3
目录 匿名函数 定义匿名函数 匿名函数的使用 内置函数 匿名函数 定义匿名函数 我们之前定义的函数都是有名函数, 我们可以通过函数名来调用 匿名函数顾名思义就是一种没有绑定函数名的函数, 使用一次既被 ...
- Python3 函数进阶2
目录 迭代器 可迭代对象 迭代器对象 总结和补充 列表推导式 字典生成式 zip()函数 递归 迭代器 迭代器是访问容器类数据类型元素的一种方式 迭代器是一个可以记住遍历的位置的对象 迭代器对象从容器 ...
- python3函数进阶
1.命名空间和作用域 命名空间 加载 内置命名空间 python解释器自带的变量和函数 开启python解释器自动加载内置命名空 ...
- 洗礼灵魂,修炼python(25)--自定义函数(6)—从匿名函数进阶话题讲解中解析“函数式编程”
匿名函数进阶 前一章已经说了匿名函数,匿名函数还可以和其他内置函数结合使用 1.map map():映射器,映射 list(map(lambda x:x*2,range(10))) #把range产生 ...
- 10.Python初窥门径(函数进阶)
Python(函数进阶) 一.函数的传参(接上期) 形参角度(一共四种,后两种) 动态参数(万能参数)* # 定义一个函数时,*所有的位置参数聚合到一个元组中 def func(*args): # * ...
- 全面系统Python3入门+进阶课程 ✌✌
全面系统Python3入门+进阶课程 (一个人学习或许会很枯燥,但是寻找更多志同道合的朋友一起,学习将会变得更加有意义✌✌) 无论是大数据.人工智能还是机器学习,Python都是最热门的首选语言 ,这 ...
- 深入理解javascript函数进阶系列第一篇——高阶函数
前面的话 前面的函数系列中介绍了函数的基础用法.从本文开始,将介绍javascript函数进阶系列,本文将详细介绍高阶函数 定义 高阶函数(higher-order function)指操作函数的函数 ...
- python3函数
一.python3函数 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.可以自己创建函数,这被叫做用户自定义函数. 1.定义函数规则 函 ...
随机推荐
- Salesforce学习之路(十一)Aura组件属性<aura:attribute />
1. <aura:attribute />语法 Aura组件属性类似与Apex中类的成员变量(或者说Java中类的成员变量).他们是组件在特定的实例上设置的类型化字段,可以使用表达式语法从 ...
- 记录一次在Github写博客时的报错和解决方法
前几天刚刚搭建好了Github博客,打算用作记录Go语言学习笔记.由于在此前我没有使用过markdown语法写过博客,所以跟着文档了解了格式就想试试, 发表第一篇博客.markdown编辑器我用的是T ...
- Python input函数使用
本文链接:https://www.cnblogs.com/zyuanlbj/p/11905475.html 函数定义 def input(*args, **kwargs): # real signat ...
- css3布局-圣杯布局
圣杯布局he双飞翼布局都是解决两边固定款中间自适应的三栏布局 圣杯布局为了中间div内容不被别的内容覆盖,将中间div设置了左右的内边距后,将左右两个div用相对布局position: relativ ...
- 领扣(LeetCode)二叉树的中序遍历 个人题解
给定一个二叉树,返回它的中序 遍历. 示例: 输入: [1,null,2,3] 1 \ 2 / 3 输出: [1,3,2] 进阶: 递归算法很简单,你可以通过迭代算法完成吗? 递归的思路很简单,不再累 ...
- 如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
缓存雪崩 数据未加载到缓存中,或者缓存同一时间大面积的失效,从而导致所有请求都去查数据库,导致数据库CPU和内存负载过高,甚至宕机. 比如一个雪崩的简单过程: 1.redis集群大面积故障 2.缓存失 ...
- opencv resize图片为正方形尺寸
在深度学习中,模型的输入size通常是正方形尺寸的,比如300 x 300这样.直接resize的话,会把图像拉的变形.通常我们希望resize以后仍然保持图片的宽高比. 例如: 如果直接resize ...
- Flow入门初识
Flow是facebook出品的JavaScript静态类型检查工具. 由于JavaScript是动态类型语言,它的灵活性也会造成一些代码隐患,使用Flow可以在编译期尽早发现由类型错误引起的bug, ...
- 【前端】 在前端利用数学函数知识+box-shadow解波浪图形
序 今天正在刷数学函数相关题目,刷到了下面这篇文章,哇哦-有意思. 利用cos和sin实现复杂的曲线.传送门在下面. CSS 技巧一则 -- 在 CSS 中使用三角函数绘制曲线图形及展示动画 正巧在复 ...
- 在Spring Security框架下JWT的实现细节原理
一.回顾JWT的授权及鉴权流程 在笔者的上一篇文章中,已经为大家介绍了JWT以及其结构及使用方法.其授权与鉴权流程浓缩为以下两句话 授权:使用可信用户信息(用户名密码.短信登录)换取带有签名的JWT令 ...