上周内容回顾
与**在实参的作用
如果我们在实参前面加星号,本质是将实参进行for循环 然后得出来的值当做实参传入形参 当然*args后可以跟多个可循环的数据类型 如果是字典只传入k **kwargs只能使用字典 表示将k=v的的格式传入
# 列表上使用
def func(*args, **kwargs):
print(args)
print(kwargs)
l1 = [1, 2, 3, 4, 5, 6]
func(*l1) # (1,2,3,4,5,6)
# 字符串上使用
def func(*args, **kwargs):
print(args)
print(kwargs)
s1 = 'heihei'
func(*s1) # ('h', 'e', 'i', 'h', 'e', 'i')
# 字典上使用
def func(*args, **kwargs):
print(args)
print(kwargs)
d1 = {'name': 'joekr', 'age': 18}
func(**d1) # {'name': 'joker', 'age': 18}
func(name='joker', age=18) # {'name': 'joker', 'age': 18}
命名关键字的参数(了解)
1.在形参*args的后面
def func(name,age,*args,c):
print(name,age,args,c)
func('joker',18,'jason',18) # 会报错
func('joker',18,'jason',18,c='lisa')
2.2.如果形参中还有**kwargs 那就必须在它的前面
def func(name, age, *args, c,**kwargs):
print(name, age, args, c,kwargs)
func('joker',18,'jason',18,c=666,name = 'lisa')
名称空间
1.内置名称空间
python解释器启动就是创建的空间
eg:len() input() print()
2.全局名称空间
py文件运行代码过程所产生的名字都会存到该空间
普通代码里的变量名
分支结构里的变量名
循环结构里的变量名
定义函数的函数名
定义的函数类名
3.局部名称空间
函数体代码运行时产生的名字都会存入该空间
名称空间存活周期
1.内置名称空间存活周期 解释器运行就创建 关闭则销毁
2.全局名称空间 py文件运行时创建 py文件结束则销毁
3.局部名称空间 函数体代码运行时创建 函数体代码结束则销毁
名字查找顺序与作用域
'''查找名字时必须要看自己在那个名称区域'''
1.当前在全局名称空间
全局名称空间>>>:内置名称空间
2.当前在局部名称空间
局部名称空间>>>:全局名称空间>>>:内置名称空间
ps:名字顺序查找时默认情况下是不能颠倒 只能是:局部>>>:全局>>>:内置
作用域
1.内置名称空间
在程序任意位置都能使用(全局有效)
2.全局名称空间
在程序任意位置都能使用(全局有效)
3.局部名称空间
在各自的局部空间能使用(局部有效)
局部名称空间复杂情况
1.局部空间只能各自使用各自对的 默认情况下双方不能共享 否则会报错
def func():
name = 'jason'
print(age)
def func1()
age = 18
print(name)
func()
func1()
函数在定义阶段名字就固定死了
global与nonlocal关键字
1.关键字:global
x = 111
def func():
global x
x = 222
func()
print(x) # 222
局部修改全局名称空间不可变类型的数据 需要使用关键字global声明
如果是可变类型 则不用关键字声明
2.关键字:nonlocal
def func():
x = 111
def func1():
nonlocal x
x = 666
func1()
print(x) # 666
func()
在内层局部空间局部空间修改外层局部名称空间的不可变类型
函数名多种使用方式
1.函数名可以被用来多次赋值 函数名与变量名一致
2.函数名可以用来当做函数的实参
3.函数名也可以用来当做函数的返回值
4.函数名还可以当做容器类型存储里面的数据值
闭包函数的简介
1.必须在函数内的函数
2.内部函数使用了外部函数名称空间名字
必须符合上述两点的函数才能称之为闭包函数
闭包函数的实用
def index(name)
def func()
print(name)
return func
res = index('jason')
装饰器简介
1.装饰器本质
是在不改变装饰对象原来'调用方式'和'内部代码'的情况下给装饰对象添加新功能
2.装饰器原则
对修改封闭 对扩展开放
装饰器的固定模板
def outer(func_name):
def inner(*args, **kwargs):
print('执行被装饰对象之前可以做的额外操作')
res =func_name(*args, **kwargs)
print('执行被装饰对象之后可以做的额外操作')
return res
return inner
装饰器语法糖
from functools import wraps
def outer(func_name):
@wraps(func_name) # 仅仅为了让装饰器不容易被发现 做到真正的以假乱真
def inner(*args, **kwargs):
print('执行被装饰对象之前可以做的额外操作')
res =func_name(*args, **kwargs)
print('执行被装饰对象之后可以做的额外操作')
return res
return inner
@outer # func = outer(真正的函数名func)
def func(*args, **kwargs):
print('from func')
func()
多层装饰器
'''
语法糖的功能
会自动将下面紧挨着的函数名当做参数传递@符号后面的函数名(加括号调用)
涉及多个语法糖装饰一个函数名
从下往上执行 最后一个语法糖才会做重命名操作
'''
def outter1(func1): # func1 = wrapper2函数名
print('加载了outter1')
def wrapper1(*args, **kwargs):
print('执行了wrapper1')
res1 = func1(*args, **kwargs)
return res1
return wrapper1
def outter2(func2): # func = wrapper3函数名
print('加载了outter2')
def wrapper2(*args, **kwargs):
print('执行了wrapper2')
res2 = func2(*args, **kwargs)
return res2
return wrapper2
def outter3(func3): # func3 = 真正的index函数
print('加载了outter3')
def wrapper3(*args, **kwargs):
print('执行了wrapper3')
res3 = func3(*args, **kwargs)
return res3
return wrapper3
@outter1 # index = outter1(wrapper2)
@outter2 # wrapper2 = outter2(wrapper3)
@outter3 # wrapper3 = outter3(真正的函数名)
def index():
print('from index')
index()
执行结果
加载了outter3
加载了outter2
加载了outter1
执行了wrapper1
执行了wrapper2
执行了wrapper3
from index
有参装饰器
当你编写一个装饰器时 这个装饰器内部需要外界传入额外的数据来控制代码的一个分支 就需要给原来的装饰器模板在套一层 然后用函数给语法糖添加额外的数据 那么你的装饰器就跟原来的一模一样 这就是有参装饰器
# 需求:在使用装饰器进行用户校验时,我可以随意切换数据的来源,无论是字典、列表还是文件
# 1.先定义一个outer函数
def outer(condition): # 4.字典传给了condition
def login_auth(function_name): # 5.执行login_auth函数 无法添加更多的形参,只能接收一个被装饰对象的函数名
def inner(*args, **kwargs): # 无法添加参数,因为它是专门用来给被装饰器对象传参的
username = input('please your username>>>:').strip()
password = input('please your password>>>:').strip()
# 根据用户需求执行不同的代码
if condition == '字典':
print('使用字典作为用户数据来源,进行比对')
elif condition == '列表':
print('使用列表作为用户数据来源,进行比对')
elif condition == '文件':
print('使用文件作为用户数据来源,进行比对')
else:
print('其他操作情况')
return inner
return login_auth # 6.返回login_auth
@outer('字典') # 3.先看outer函数(),执行outer函数
def index(): # 2.定义一个index函数
print('hello word')
index()
递归函数
函数不仅可以嵌套定义,还可以嵌套调用,即在调用一个函数的过程中,函数内部又调用另一个函数,而函数的递归调用指的是在调用一个函数的过程中又直接或间接地调用该函数本身
概念 函数直接调用和间接调用
1.直接调用
def func()
pass
func()
func()
2.间接调用
def func()
pass
index()
def index()
pass
func
func()
递归函数应用场景
递推:一层一层往下寻找答案
回溯:根据已知的条件推导最终结果
递归函数
1.递归函数每次调用时都必须要比上一次简单
2.并且递归函数最终必须要一个明确结束条件
l1 = [1, [2, [3, [4, [5, [6, [7, [8, [9, [10]]]]]]]]]]
def get_num(l1):
for i in l1:
if isinstance(i, int):
print(i)
else:
get_num(i)
get_num(l1)
算法之二分法
什么是算法
算法就是能解决一些问题的方法
算法永远都在精进 很少有最完美的算法
二分法的缺陷
二分法查找的数据必须是有序
l1 = [11,22,34,56,66,115,425,521,565,785,999,1024,1325]
def index(l1, target_num):
if len(l1) == 0: # 要有一个明确的结束条件 列表数据值为0 结束
print('没找到')
return
middle_index = len(l1) // 2 # 取出列表中间的数
middle_value = l1[middle_index]
if target_num > middle_value: # 判断中间数据值与目标数据值谁大谁小
right_l1 = l1[middle_index + 1:] # 要查找的目标数据值在右 切取右边
print(right_l1)
index(right_l1, target_num)
elif target_num < middle_value:
left_l1 = l1[:middle_index] # 要查找的目标数据值在左 切取左边
print(left_l1)
index(left_l1, target_num) # 递归函数
else:
print('找到了', target_num)
index(l1, 999
三元表达式
偷懒写法 为了减少代码行数
雏形
eg:name = input('name>>>:')
if name = 'jason'print('欢迎')
else:print('滚蛋')
三元表达式:仅限于二选一 不建议嵌套使用
三元表达式语法结构
数据值1 if 条件 else 数据值2
如果if后面条件成立 则用if前面数据值1
如果if后面条件不成立 则用else后面的额数据值2
各自生成式
1.列表生成式
列表生成式原理 先执行for循环 在将一个个数据值交给for前面处理 同时还支持if判断 先for循环 数据给if进行判断 结果Ture后交给for前面处理
list = ['jason', 'kevin', 'joker', 'tong', 'lisa']
new_list = [name + 'NB' for name in list]
new_list = [name + '_NB' for name in list if name =='jason']
2.字典生成式
dict = {i: 'jaosn' for i in range(5)}
dict = {i: 'jason' for i in range(5)if i == 4}
3.集合生成式
set = {i for i in range(5)}
set = {i for i in range(5)if i == 2}
生成器可以使用for跟if 但是不能出现else 因为for跟if都能使用else 会出现歧义
匿名函数
匿名函数就是没有函数名的函数
匿名函数主要搭配一些内置方法使用 用于减少代码 单独使用性质并不大
1.语法结构
lamdba 形参:返回值
2.具体调用
(lamdba x: x + 1)
3.实际应用
nax() 求最大值
new_dict = {'jason': 666,'kevin': 123,'Bason': 99999, 'zero': 888}
res = max(new_dict)
print(res) # zero
不使用匿名函数时会按照字典的k进行比对
如果是字符串的话是按照ASCII码表进行比对
大写字母A-Z 65-90
小写字母a-z 97-122
res = max(new_dict, key=lambda k: new_dict.get(k))
print(res) # Bason
匿名函数for取用k对应的数据值来比对 但并不会返回k对应的数据值 会以数据值对应的k进行返回
重要内置函数
map 映射
map底层也是for循环 帮你把一些东西经过处理变成另一种东西
filter 过滤
配合匿名函数进行删选过滤
reduce 求所有数之和
内部机制内部机制第一次取的时候会取两个进行比对 然后将取出的第二个的数依次跟后面的进行比对 还可以在次指定一个值在尾部与比对完得出的数相加
zip 拼接多个数据值 但必须是支持for循环的
按照位置对应拼接 如果数据的个数不一样 就按照最短个数拼接 能拼接几个就拼接几个