学习python-周总结03
周总结
一、 * 与 ** 在实参和形参的作用
| * | ** | |
|---|---|---|
| 形参作用 | 位置参数多余的部分传值给*后面的变量名 | 关键字参数多余的部分传值给**后面的变量名 |
| 实参作用 | 利用for循环将每个列表的数据值、字符串的字符、字典的k值分开再组织成元组的形式传值给函数体代码 |
就是将字典的每个K:V键值对取出转化成关键字实参的方式。 |
二、命名关键字参数(冷门了解)
1. def func(a,b,*args,c):
print(a,b,args,c)
func(1,2,3,4,5)#报错
func(1,2,3,4,c=5) # 1 2 (3,4) 5
命名关键字-变量名可以放在*args的后面。不过在实参的时候,该变量名要以关键字实参的方式传值到形参。
def func(a,b,*args,c,**kwargs):
pass
func(1,2,3,4,5,6,c=123,name='xz')
注意该变量不能放在**kwargs的后面,不然会报错。
三、名称空间
1.定义:就是存放变量名与数据值之间绑定关系的地方。
name = 'xz'
del name (删除不是数据值,而是变量名与数据值之间的绑定关系)
| 名称空间 | 内置名称空间 | 全局名称空间 | 局部名称空间 |
|---|---|---|---|
| 定义 | python解释器运行就会立刻创建空间 | py文件代码运行过程中产生的名字会存在这个空间 | 函数体代码一运行过程中产生的名字都会存入该空间 |
| 用法 | 直接拿来用的内置函数 | 普通代码里面的变量名(分支结构,循环结构,定义函数的函数名,定义类的类名) | 函数体运行后的变量名。 |
2.名称空间的存活周期
| 创建 | 销毁 | |
|---|---|---|
| 内置名称空间 | 解释器运行 | 解释器关闭 |
| 全局名称空间 | py文件运行 | py文件结束 |
| 局部名称空间 | 函数体代码运行 | 函数体代码结束 |
3.名字查找顺序
名字查找顺序之前一定要清楚自己所在的名称空间是什么。
当前处于全称名称空间时: 全称名称空间 >>> 局部名称空间
就在全称名称空间找那个名字,如果没有就去内置名称空间里面找。
当前处于局部名称空间时: 局部名称空间 >>> 全称名称空间 >>> 局部名称空间
就在当前的局部名称空间找名字,如果没有就去全称名称空间找,还没有最后去内置名称空间找。如果内置都找不到,那就报错!
4.局部名称空间复杂情况
注意:各自局部名称空间默认下情况下不能彼此共享名字。
函数嵌套情况就很特殊。
? 它可以在内存局部名称空间调用外存名称空间。外层名称空间调用最外层名称空间。最后没有局部名称空间后调用全局名称空间。
x = 1
def func1():
x = 2
def func2():
x = 3
def func3():
x = 4
func3()
func2()
func3()
5.global与nonlocal关键字
global 就是将全局名称空间的变量名变成局部名称空间里的变量名(可变类型可以不用关键字,不变类型需要关键字)
nonlocal 就是内层局部名称空间的变量名修改外层局部名称空间里的变量名(不可类型)。
四、函数名的多种使用方式
| 函数名使用方式 |
|---|
| 1.函数名可以被用来多次赋值(函数名与变量名使用一致) |
| 2.函数名可以当做函数实参 |
| 3.函数名可以当做函数名的返回值 |
| 4.函数名可以当做容器类型里面的数据值:l1 = [1,2,3,4,func] |
五、闭包函数
1.闭包函数简介:
- 定义在函数内部的函数
- 内部函数使用了外部函数名称空间里的名字
注意:如果有内部函数情况下,运行外部函数不会立马结束,而是等内部函数全部结束才结束。
2.闭包函数的实际应用:
函数体代码传值的方式有两种:
- 形参
- 闭包函数
def index():
username = 'xz'
def func():
print(username)
return func
res = index()
res()
六、装饰器
1.装饰器的简介
- 在不改变被装饰器对象原来的
调用方式和内部代码的情况下给被装饰对象的添加新的功能。
2.装饰器的原则
- 不能修改代码,只能扩展代码
时间戳:
import time
print(time.time())
'''时间戳(秒数):当前距离1970年1月1日0时0分0秒'''
time.sleep(3)
print('3秒后我出来了')
'''让程序原地等待三秒'''
3.装饰器的前期推导
-
index()前后加个时间戳是不改变它的调用方式和内部代码。
import time def index(): print('运行index函数体代码') start_time = time.time() index() end_time = time.time() print('函数执行的时间:',end_time - start_time)注意:不利于多个index函数需要统计时间。
-
多个相同函数需要统计时间,需要封装成函数。
import time def index(): print('运行index函数体代码') def get_time(): start_time = time.time() index() end_time = time.time() print('函数的执行时间是:', end_time - start_time) get_time()注意:封装后,但是不能满足不同函数的统计时间。
-
多个不同的函数需要统计时间,可以封装后调用形参(动态传参)
import time def index(): print('运行index函数体代码') def home(): print('运行home函数体代码') def get_time(a): start_time = time.time() a() end_time = time.time() print('函数的执行时间是:', end_time - start_time) get_time(index) get_time(home) '''传参的过程中我们要注意形参的个数问题:引用* 与 **''' 如果在a(*args, **kwargs)的话会报错,原因是get_time函数没法识别a()里面是什么东西。注意:这样会改变之前的调用方式!!!如果不能直接用形参的方式,那就用闭包函数。
4.装饰器各个版本
如果index和home都有形参,则就不能用形参的方式传值,而是用闭包函数来做。
def outer(a):
def get_time(*args, **kwargs)
start_time = time.time()
a(*args, **kwargs)
end_time = time.time()
print('函数的执行时间是:', end_time - start_time)
return get_time
res = outer(index)
res()
res1 = outer(home)
res1()
'''注意:这样还有不满足装饰器的条件,调用方式改变。'''
我们可以将变量名重命名和函数名一样解决了调用方式不一样问题。
def outer(a):
def get_time():
start_time = time.time()
a()
end_time = time.time()
print('函数的执行时间是:', end_time - start_time)
return get_time
index = outer(index)
index()
home = outer(home)
home()
5.装饰器的固定模板
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
inner = outer()
inner()
6.装饰器语法糖
语法糖的功能就是紧挨着的函数名(装饰对象)当做参数传递给@符号后面的函数名(加括号调用)
#装饰器语法糖
import time
@outer
def home():
print('from home')
return 'home的返回值'
home()
7.help
def index():
pass
help(index)
8.多层装饰器
def outer1(func1):
print('加载outer1')
def wrapper1(*args, **kwargs):
print('执行了wrapper1')
res1 = func1(*args, **kwargs)
return res1
return wrapper1
def outer2(func1):
print('加载outer2')
def wrapper1(*args, **kwargs):
print('执行了wrapper2')
res2 = func21(*args, **kwargs)
return res2
return wrapper2
def outer1(func3):
print('加载outer3')
def wrapper1(*args, **kwargs):
print('执行了wrapper3')
res3 = func31(*args, **kwargs)
return res3
return wrapper3
@outer1 # index = outer1(wrapper2)
@outer2 # wrapper2 = outer2(wrapper3)
@outer3 # wrapper3 = outer3(index)
def index():
print('hello world!')
index()
9.有参装饰器
def transfor(condition, type_user):
def outer(func_name):
def inner(*args, **kwargs)
if type_user == 'xz':print('VIP')
if condition == '权限1':
print('可以打开权限1,进入其中使用其功能。')
elif condition == '权限2':
print('可以打开权限2,进入其中使用其功能。')
elif condition == '权限3':
print('可以打开权限3,进入其中使用其功能。')
else:
print('没有别的方式!')
return inner
return outer
@transfor('权限1', type_user)
def inner():
print('执行inner函数体代码')
inner()
'''目的给装饰器传递更多额外的数据'''
四、算数二分法
就是解决问题的方法。
就是将有序数组一分为二,取中间那个数值与目标数值比较。目标数值大,则在这中间的数往右半边找。目标数小则往左半边找。再从左半边/右半边取中间的数值与目标数值比较,以此类推,缩短查找的空间,步步接近与目标数相近的数值最后找到目标数值。
五、三元表达式
主要减少了代码的行数
'缩短单横的条件语句'
eg:
if username == 'xz':print('欢迎')
else:print('抱歉!')
'三元表达式:仅限于二选一情况(if...else)并且不建议嵌套使用'
eg:
print('欢迎') if username == 'xz' else print('抱歉')
'''
三元表达式语法结构:
值1 if 条件 else 值2
如果if后面的条件成立,则使用if前面的值
如果if后面的条件不成立,则使用else后面的值
'''
六、生成式
1.列表生成式/字典生成式/集合生成式
#列表生成式
name_list = ['xz', 'wyb', 'bx', 'yyds']
#给上述列表所有的数据值加上s的后缀
#先执行for循环,然后将一个个数据值交给for循环前面的拼接处理,最后在整理成一个新列表。
new_list = [name + 's' for name in name_list]
print(new_list)
#如果有if判断语句就for循环之后先if判断。
new_list = [name + 's' for name in name_list if name != 'xz']
print(new_list)
----------------
#字典生成式
#for循环将i作为K值,然后将每个K值循环到后面的if判断,判断后的值返回到for循环前面的代码中执行。
new_dict = {i: 'xz' for i in range(10) if i == 6}
print(new_dict) #{6:'xz'}
#集合生成式
new_set = {i for i in range(10) if i == 6}
print(new_set)
4.元组
元组没有生成式,只有生成器就是迭代器。
七、匿名函数
-
匿名函数就是没有函数名的函数
-
语法结构: lambda 形参 : 返回值
-
直接调用: (lambda x : x + 1)(123)
-
命名调用:res = lambda x : x + 1
-
应用场景:
通常要配合其他函数一起使用,用于减少代码。
八、匿名函数在内置函数中是使用
-
max() 最大值/min()最小值
min()'方法返回字符串中最小的字母' max()'会根据提供的函数对指定序列做映射' l1 = [1,2,3,4,5] res = max(l1) print(res) # 5dict1 = { 'jason': 100, 'aj': 123, 'Bason': 9999, 'zero': 888 } #方式一:直接用函数 #传入一个形参K def index(k): return dict1.get(k) res = max(dict1, key = index) print(res) #方式二:用匿名函数 #得到K值对应的V值,然后将数据传到前面的dict1中比较大小。 res = max(dict1, key = lambda k: dict1.get(k)) print(res)
九、重要的内置函数
-
reduce() 求和
函数会对参数序列中元素进行累积。l2 = [1, 2, 3] # 需求:求列表中所有数据值的和方式1 : for循环
s = 0 for i in l2: s += i print(s)方式2 : sum()
res = sum(l2) print(res)方式3 : reduce()
from functools import reduce #用匿名函数,l2后面是可以添加数据值的。 res = reduce(lambda x, y: x + y, l2, 100) print(res) -
map()映射
l1 = [11, 22, 33, 44, 55, 66] # 需求:将列表中所有的数据值自增20方式1:for循环
new_list = [] for i in l1: i += 10 new_list.append(i) print(new_list)方式2:列表生成式
new_list = [i+10 for i in l1] print(new_list)方式3:map函数
res = map(lambda i : i = 10, l1) print(res) ---------- def index(a): return a + 10 res = map(index,l1) print(list(res)) -
filter() 过滤
用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成新的列表l1 = ['xz', 'wyb', 'bx', 'yyds'] # 需求:移除数据值里面的yyds方式1:for循环
for i in l1: if i == 'yyds': l1.remove(i) print(l1)方式2:列表生成式
new_list = [i for in l1 if i != 'yyds'] print(new_list)方式3:filter()
res = filter(lambda a : a != 'xz', l1) print(res)#迭代器形式 print(list(res))#这里需要转换成列表形式 -
zip()
- 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象。
- 如果各个迭代器的元素个数不一样,则返回列表长度与最短的对象相同,利用*操作符可将元组解压成列表
>>> a = [1,2,3] >>> b = [4,5,6] >>> a1, a2 = zip(*zip(a,b)) >>> list(a1) [1, 2, 3] >>> list(a2) [4, 5, 6]-
元组根据一一对应然后组成一个元组,再用list转化成列表里的元组。
l1 = [1, 2, 3] l2 = ['xz','wyb','bx'] res = zip(n1, n2) print(res) #print(list(res)) '运行结果: [(1, 'xz'), (2, 'wyb'), (3, 'bx')]' -
字符串拆开成一个个字符对应。
l1 = [1, 2, 3] l2 = ['xz','wyb','bx'] s = 'wyb' res = zip(l1,l2,s) print(list(res)) '运行结果: [(1, 'xz', 'w'), (2, 'wyb', 'y'), (3, 'bx', 'b')]' -
元素个数与最短的列表一致。
l1 = [1, 2, 3] l2 = ['xz','wyb','bx'] s1 = 'xz' res = zip(l1, l2, s1) print(list(res)) '运行结果: [(1, 'xz', 'x'), (2, 'wyb', 'z')]'
十、递归函数
1.概念:函数可以直接或者间接调用自己>>>>递归调用
def index():
print('oooooo')
index()
index()
'''超过了系统给定的调用次数会报错'''
def index();
print('oooo')
func()
def func():
print('000000')
index()
func()
'''相互间接调用'''
2.递归函数真正的应用场景
递归:一层层忘下寻找答案
回溯:根据已知条件退出最终结果
递归函数
- 每次调用的时候都比上一次更接近结果
- 递归函数最终都需要有个明确的结束条件。