作者:祥荣华贵 | 来源:互联网 | 2023-07-06 13:54
昨日学习回顾闭包函数需要满足两个条件:条件1:定义在函数体内部的函数条件2:内部函数使用了外部函数名称空间中的名字作用:函数体代码得到外界的数据可以直接通过形参
昨日学习回顾
闭包函数
需要满足两个条件:
条件1:定义在函数体内部的函数
条件2:内部函数使用了外部函数名称空间中的名字
作用:
函数体代码得到外界的数据可以直接通过形参
而闭包是给函数体代码传参的第二种方式
'''
方式1
直接通过当前函数的形参
def index(name):
print(name)
方式2
通过闭包函数的形式包给内部函数
def outer(name):
# name = 'jason'
def index():
print(name)
return index
'''
装饰器的内容
装饰器
定义:
在不改变被装饰对象的'原代码'及'调用方式'的情况下增加新的功能
# 记录一个装饰器模板
def outer(func_name): # 接收被装饰对象的名字
def inner(*arg, **kwargs): # 兼容所有的函数类型
# 执行被装饰函数之前可以做的额外操作
res = func_name(*args, **kwargs)
# 执行被装饰函数之前可以做的额外操作
return res # 返回真正函数的返回值
return inner
装饰器语法糖
定义:
就是@+函数名
@outer
def index():
pass
'''
@outer的本质其实就是 inder = outer(index)
'''
右侧的index是真正的函数名
左侧的index是变量名
装饰器修复技术
# 查看函数的注释
help()
# 修复技术的主要功能就是以假乱真
from functools import warps
def outer(func_name): # 接收被装饰对象名字
@warp(func_name) # 固定搭配
def inner(*args, **kwargs)
res = func_name(*args, **kwargs)
return res
return inner
今日学习内容
多层装饰器
语法糖定义:
语法糖会将紧挨着的被装饰对象的名字当做参数自动传入装饰器函数中
def outter1(func1):
print('加载了outter1')
def wrapper1(*args, **kwargs):
print('执行了wrapper1')
res1 = func1(*args, **kwargs)
return res1
return wrapper1
def outter2(func2):
print('加载了outter2')
def wrapper2(*args, **kwargs):
print('执行了wrapper2')
res2 = func2(*args, **kwargs)
return res2
return wrapper2
def outter3(func3):
print('加载了outter3')
def wrapper3(*args, **kwargs):
print('执行了wrapper3')
res3 = func3(*args, **kwargs)
return res3
return wrapper3
@outter1
@outter2
@outter3
def index():
print('from index')
运行结果:
执行了wrapper3
执行了wrapper2
执行了wrapper1
# 得出结论
多层装饰器的装饰顺序是越靠近被装饰函数的越先调用
1
![](https://img2.php1.cn/3cdc5/3ecd/696/3ced1dbb55d35b6b.png)
有参装饰器
# 有参函数的模板
def 有参装饰器(x,y,z):
def outter(func):
def wrapper(*args, **kwargs):
res = func(*args, **kwargs)
return res
return wrapper
return outter
@有参装饰器(1,y=2,z=3)
def 被装饰对象():
pass
# 课堂内容
def outer(source_data):
def login_auth(func_name): # 不能动 只能接收一个被装饰对象名字
def inner(*args, **kwargs): # 不能动 是专门用来给被装饰的对象传参的
username = input('username>>>:').strip()
password = input('password>>>:').strip()
# 校验用户数据 数据的来源可以有很多 比如全局字典 全局列表 文本文件 数据库
# 数据的来源不同 处理方式就不同 对应的代码编写就不一样
# 分支结构处理 然后根据不同的参数提示 匹配不同的流程
if source_data == '1':
print('使用字典的方式处理数据')
elif source_data == '2':
print('使用列表的方式处理数据')
elif source_data == '3':
print('使用文件操作处理数据')
else:
print('其他操作情况')
res = func_name(*args, **kwargs)
return res
return inner
return login_auth
@outer('3')
def index():
print('from index')
index()
# 结果
username>>>:123
password>>>:123
使用文件操作处理数据
from index
"""
函数名加括号 执行优先级最高
@outer('3')
左侧是语法糖结构 右侧是函数名加括号结构
先执行函数调用 outer('3') 返回值是login_auth
在执行语法糖结构 @login_auth
发现最后还是一个普通的装饰器
有参装饰器目的仅仅是给装饰器传递额外的参数
装饰器最多就三层嵌套
from functools import wraps
@wraps(func_name)
"""
递归函数
# 概念:
在函数内部,可以调用其他函数,如果一个函数在内部调用自身本身,这个函数就是递归函数
# 直接调用自己
def index():
print('from index')
index()
index()
这样子运行就会超出最大递归深度,但是好在pycharm中有应急机制
# 间接调用自己
def index():
print('from index')
func()
def func():
print('from func')
index()
func()
'''
在递归深度的状态下是有个最大值的,一般是997或998
1000是官方给出的数据
'''
import sys
print(sys.getrecursionlimit()) # 获取默认的最大递归深度
sys.setrecursionlimit(2000) # 还可以修改最大递归深度
'但是真正的递归是要满足条件的'
1.每次递归,复杂度必须比上次降低
2.必须要有明确的结束条件
# 课堂上举的例子
需求:我想知道我们班坐在第一排的某个学生年龄
过程:
我问他多大了 他调皮不告诉我 说比后面那个同学大两岁
后面的说比他后面的大两岁
...
问到最后你一排 终于开口说 18岁
...
知道最后一排的年级回推就可以知道第一排的年级
名词:
递推:一层层往下问
回溯:根据结果推结论
'''
# 如何编写代码完成
# 目标人物的年龄 = 后一排年龄 + 2
# 后一排年龄 = 后后一排年龄 + 2
# 后后一排年龄 = 后后后一排年龄 + 2
# 后后后后一排年龄 = 18
# 将求问年龄变成函数
# age(5) = age(4) + 2
# age(4) = age(3) + 2
# age(3) = age(2) + 2
# age(2) = age(1) + 2
# age(1) = 18
# 封装函数
def get_age(n):
if n == 1:
return 18 # 有明确的结束条件
return get_age(n-1) + 2
print(get_age(4))
'''
# 另外的小例子:
计算1-100之间相加的和
按照我们之前学过的内容,可以考虑用循环做这个问题
def sum_1(n):
sum = 0
for i in range(1, n+1):
sum += i
print(sum)
sun_1(100) # 5050
然后接下来我们用递归的思路推导一下这个题
def sun_2(n):
if n > 0:
return n + sum_2(n-1)
else:
return 0
sum = sum_2(100)
print(sum) # 5050
递归函数的优点是定义简单,逻辑清晰。
理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰,所以循环也可以看成是一种特殊的递归
递归练习
l1 = [1,[2,[3,[4,[5,[6,[7,[8,[9,]]]]]]]]]
'''需求:循环打印出列表中每一个数字'''
# 写代码之前一定要先理清思路
"""
完整步骤
1.for循环大列表
2.判断元素是否是数字 如果是则打印
3.如果不是则for循环
4.判断元素是否是数字 如果是则打印
5.如果不是则for循环
6.判断元素是否是数字 如果是则打印
7.如果不是则for循环
ps:重复做一些事情 但是每次都比上一次简单一些 >>>: 递归函数
"""
def get_num(l):
for i in l:
if isinstance(i,int): # 判断某个数据是否属于某个类型
print(i)
else:
get_num(i)
get_num(l1)
'''
1
2
3
4
5
6
7
8
9
'''
算法之二分法
算法的概念:
能够对一定规范的输入,在有限时间内获得所要求的输出
大白话:
算法其实就是解决问题的有效方法
今天上课学的一个入门算法叫'二分法'
'二分法使用有前提: 数据集必须有先后顺序(升序 降序)'
# 原理
二分法原理
获取数据集中间的元素 比对大小
如果中间的元素大于目标数据 那么保留数据集的左边一半
如果中间的元素小于目标数据 那么保留数据集的右边一半
然后针对剩下的数据集再二分
如果中间的元素大于目标数据 那么保留数据集的左边一半
如果中间的元素小于目标数据 那么保留数据集的右边一半
...
例子:
l1 = [13,21,35,46,52,67,76,87,99,123,213,321,432,564]
def get_target(l1,target_num):
# 最后需要考虑找不到的情况 l1不可能无限制二分
if len(l1) == 0:
print('不好意思 真的没有 找不到')
return
# 1.获取中间元素的索引值(只能是整数)
middle_index = len(l1) // 2
# 2.判断中间索引对应的数据与目标数据的大小
if target_num > l1[middle_index]:
# 3.保留数据集右侧
l1_left = l1[middle_index+1:]
# 3.1.对右侧继续二分 重复执行相同代码 并且复杂度降低
print(l1_left)
get_target(l1_left,target_num)
elif target_num # 4.保留数据集左侧
l1_right = l1[:middle_index]
print(l1_right)
# 4.1.对右侧继续二分 重复执行相同代码 并且复杂度降低
get_target(l1_right,target_num)
else:
print('找到了',target_num)
# get_target(l1,432)
# get_target(l1,22)
get_target(l1,13)
算法拓展
冒泡排序
# 概念
"简单来说就是将一个无序的列表,从第一个元素开始与第一个元素后面的一个元素比较,大于后面的元素就交换位置,小于后面的元素就在用后面的那一个元素与下下一个元素相比"
"直到最后一个元素算是排完一轮这个过程就是是泡泡往上冒一样,故称为冒泡算法"
# 举个小例子
def bubbleSort(arr):
n = len(arr)
# 遍历所有数组元素
for i in range(n):
# Last i elements are already in place
for j in range(0, n-i-1):
if arr[j] > arr[j+1] :
arr[j], arr[j+1] = arr[j+1], arr[j]
arr = [64, 34, 25, 12, 22, 11, 90]
bubbleSort(arr)
print ("排序后的数组:")
for i in range(len(arr)):
print ("%d" %arr[i])
结果:
'''
11
12
22
25
34
64
90
'''
选择排序
# 概念
'首先在所给的未排序序列中找到最小(大)的元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的后面。以此类推,直到所有元素均排序完毕。'
'先找小的元素就是顺序排序,先找大的就是逆序排序'
# 举个小例子
A = [64, 25, 12, 22, 11] # 定义一个列表
def get_min(): # 定义一个函数
for i in range(len(A)): # for循环A列表中的元素
min_idx = i # 定义一个变量名用于接收最小元素的值
for j in range(i+1, len(A)): # 再一个for循环A列表中剩余的元素值
if A[min_idx] > A[j]: # 对之前接收的最小值与之后面的一个数进行比对
min_idx = j # 接收相比较下更小元素的值
A[i], A[min_idx] = A[min_idx], A[i]
print ("排序后的数组:")
for i in range(len(A)):
print("%d" %A[i])
get_min()
结果:
'''
排序后的数组:
11
12
22
25
64
'''
排序引入、插入排序、快速排序、希尔排序···
今天学习了算法,就学了一个递归算法,还有好多种其他的算法,还是比较有趣的