闭包函数

什么是闭包函数

闭包函数本质上就是函数嵌套和高阶函数

闭包函数的满足条件:

  • 必须嵌套函数
  • 内嵌函数必须引用外部函数的变量
  • 外部函数必须返回内嵌函数的函数对象(函数名)
# 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的更多相关文章

  1. 5 Python3 函数进阶&迭代器与生成器

    1.函数进阶 1.1.名称空间 又名name space, 顾名思义就是存放名字的地方,存什么名字呢?举例说明,若变量x=1,1存放于内存中,那名字x存放在哪里呢?名称空间正是存放名字x与1绑定关系的 ...

  2. Python3 函数进阶3

    目录 匿名函数 定义匿名函数 匿名函数的使用 内置函数 匿名函数 定义匿名函数 我们之前定义的函数都是有名函数, 我们可以通过函数名来调用 匿名函数顾名思义就是一种没有绑定函数名的函数, 使用一次既被 ...

  3. Python3 函数进阶2

    目录 迭代器 可迭代对象 迭代器对象 总结和补充 列表推导式 字典生成式 zip()函数 递归 迭代器 迭代器是访问容器类数据类型元素的一种方式 迭代器是一个可以记住遍历的位置的对象 迭代器对象从容器 ...

  4. python3函数进阶

    1.命名空间和作用域 命名空间     加载         内置命名空间             python解释器自带的变量和函数             开启python解释器自动加载内置命名空 ...

  5. 洗礼灵魂,修炼python(25)--自定义函数(6)—从匿名函数进阶话题讲解中解析“函数式编程”

    匿名函数进阶 前一章已经说了匿名函数,匿名函数还可以和其他内置函数结合使用 1.map map():映射器,映射 list(map(lambda x:x*2,range(10))) #把range产生 ...

  6. 10.Python初窥门径(函数进阶)

    Python(函数进阶) 一.函数的传参(接上期) 形参角度(一共四种,后两种) 动态参数(万能参数)* # 定义一个函数时,*所有的位置参数聚合到一个元组中 def func(*args): # * ...

  7. 全面系统Python3入门+进阶课程 ✌✌

    全面系统Python3入门+进阶课程 (一个人学习或许会很枯燥,但是寻找更多志同道合的朋友一起,学习将会变得更加有意义✌✌) 无论是大数据.人工智能还是机器学习,Python都是最热门的首选语言 ,这 ...

  8. 深入理解javascript函数进阶系列第一篇——高阶函数

    前面的话 前面的函数系列中介绍了函数的基础用法.从本文开始,将介绍javascript函数进阶系列,本文将详细介绍高阶函数 定义 高阶函数(higher-order function)指操作函数的函数 ...

  9. python3函数

    一.python3函数 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.可以自己创建函数,这被叫做用户自定义函数. 1.定义函数规则 函 ...

随机推荐

  1. requests模拟登陆的三种方式

    ###获取登录后的页面三种方式: 一.实例化seesion,使用seesion发送post请求,在使用他获取登陆后的页面 import requests session = requests.sess ...

  2. 理解MySQL数据库事务-隔离性

    Transaction事务是指一个逻辑单元,执行一系列操作的SQL语句. 事务中一组的SQL语句,要么全部执行,要么全部回退.在Oracle数据库中有个名字,叫做transaction ID 在关系型 ...

  3. 机器学习 TensorFlow 实现智能鉴黄

    前言 最近在做一款图床服务,关注公号的小伙伴一定记得小柒曾说过,会在周末放出的,不好意思放大家鸽子了.之所以一直没敢放出,是因为鉴黄接口一直没调试好,虽然我对公号的小伙伴百分之百信任,奈何互联网鱼龙混 ...

  4. 十二、powerManager

    PowerManger模块主要负责电池工作状态,电量监测,充放电管理. 1.1     初始化 在PowerInit()接口中完成了powerManager模块的初始化,在初始化的末端,进行了多个AD ...

  5. Oracle 环境配置

    一.首先要查看IP地址是否配置成功,网络是否连接 [root@admin ~]# ifconfig | head -2 若不成功,打开配置文件: vi /etc/sysconfig/network-s ...

  6. PostGIS 递归方法

    在Oracle数据库中,有可以实现递归的函数 select * from table_name start with [condition1] connect by [condition2] 最近发现 ...

  7. C#音频截取与原文匹配

    1.需求 上传一个音频文件(例如英语听力的音频)与音频对应的原文word文档.大概估算音频中一段对话到另一端对话的时间间隔,将音频截取为不同对话的小音频文件,通过百度语音识别转换成英文,然后与原文对比 ...

  8. JAVA,Python代码是编译执行还是解释执行?

    转载地址:http://blog.csdn.net/zv3e189os5c0tsknrbcl/article/details/78661641 有人在讨论 Python 代码是编译执行还是解释执行?这 ...

  9. linux常规网卡配置正确,但是出不了路由的解决方法

    netstat -rn #查看是网关  route add default gw 192.168.128.2 dev eth0  # 手动加入网关地址   此类情况容易出现在双网卡配置后

  10. linux中Nginx安装

    linux中Nginx安装 编译安装 ​ Nginx的优点太多,这里不再赘述,详情请看这篇博客深入理解nginx. ​ Nginx的安装有rpm包安装.编译安装和docker安装.本文将介绍编译安装方 ...