闭包函数

什么是闭包函数

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

闭包函数的满足条件:

  • 必须嵌套函数
  • 内嵌函数必须引用外部函数的变量
  • 外部函数必须返回内嵌函数的函数对象(函数名)
# 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. mybatis的parameterType为map,map里带有多个list

    我写这个主要是为了解决sql注入 原sql有sql注入, 结果:select req_msg_id from account_message_info where req_msg_id in ('12 ...

  2. TestNG+Maven+IDEA 环境配置+入门

    一.环境配置 1.安装IDEA(参考:https://blog.csdn.net/m0_38075425/article/details/80883078) 2.在Prefernces,通过Plugi ...

  3. 二 linuk系统安装

    一 VM虚拟机安装与使用 安装: VM官网:www.vmware.com 不需要太高版本 安装较为简单,选典型安装,别放c盘即可 使用 1.创建虚拟机时,把每个处理器的内核数量调高(我调为8),注意别 ...

  4. vant-ui的van-area使用

    由于官方例子中并没有太多详情,因此记录之,方便以后使用. 1.配置 :area-list="areaList",以初始化全部省市区的数据,其中area.js文件在官方可以下载,放于 ...

  5. Python装饰器的使用

    对于python编程人员,装饰器的使用肯定是必不可少的. 装饰器分为系统定义装饰器和自定义装饰器:系统定义装饰器:@classmethod:类方法装饰器  @staticmethod:   静态方法装 ...

  6. Nvm安装步骤

    下载地址 https://github.com/coreybutler/nvm-windows/releases 解压压缩包,后是一个.exe结尾的安装文件,双击安装, 选择安装位置,如下图: 设置n ...

  7. TypeScript SDK 和 REST API

    在本文中,我们将讨论CUBA平台中已经存在很长时间的一个功能,但是很多人还不知道,这就是前端SDK生成器,并了解它如何与CUBA的REST API插件一起使用. Java+JavaScript - 在 ...

  8. SpringBoot源码学习系列之异常处理自动配置

    SpringBoot源码学习系列之异常处理自动配置 1.源码学习 先给个SpringBoot中的异常例子,假如访问一个错误链接,让其返回404页面 在浏览器访问: 而在其它的客户端软件,比如postm ...

  9. [从今天开始修炼数据结构]串、KMP模式匹配算法

    [从今天开始修炼数据结构]基本概念 [从今天开始修炼数据结构]线性表及其实现以及实现有Itertor的ArrayList和LinkedList [从今天开始修炼数据结构]栈.斐波那契数列.逆波兰四则运 ...

  10. .NET Core开发的iNeuOS工业互联网平台,发布 iNeuDA 数据分析展示组件,快捷开发图形报表和数据大屏

    目       录 1.      概述... 2 2.      演示信息... 2 3.      简单介绍... 3 4.      产品特点... 4 5.      价值体现... 5 1. ...