DAY12 三大神器
一. 迭代器
1.1 认识迭代器
- 迭代器是容器:程序中无法直接创建一个迭代器,只能将别的序列转换成迭代器
- 特点:打印迭代器无法查看所有的元素,也无法获取元素的个数;获取元素的时候每次只能获取最前面的元素,而且元素取一个就少一个
i1 = iter('abc123')
print(i1) # <str_iterator object at 0x0000027D5B989400>
print(type(i1)) # <class 'str_iterator'>
# print(len(i1)) 报错,无法统计个数
i2 = iter([1, 2, 3])
print(i2) # <list_iterator object at 0x0000025F6D657940>
i3 = iter({'a': 10, 'b': 20, 'c': 30})
print(i3) # <dict_keyiterator object at 0x0000026D91D94220>
1.2 查 - 获取元素
迭代器不管以什么样的方式获取到了某个元素,那么这个元素一定会从迭代器中消失
- 查单个:next(迭代器) - 获取迭代器中最前面的那个元素
print(next(i1)) # 'a'
print(next(i1)) # 'b'
print(next(i2)) # 1
print(next(i2)) # 2
print(next(i2)) # 3
# print(next(i2)) # 报错,取完了
print(list(i1)) # ['c', '1', '2', '3'],由剩下的元素转换
print(list(i2)) # []
print(list(i3)) # ['a', 'b', 'c']
# print(next(i3)) # 报错!转换成列表,获得了元素,从迭代器中消失
- 遍历
i3 = iter([10, 20, 30])
for x in i3:
print(x)
二. 生成器
2.1 认识生成器
- 生成器也是容器;其他容器是直接保存多个数据,生成器保存的是产生多个数据的算法
- 生成器获取数据的方式和特点和迭代器一样
2.2 创建生成器
调用一个带有yield关键字的函数就可以得到一个生成器对象
def func1():
print('++++++')
print('======')
yield # 函数内位置任意,return后也是,if内也是
return 100
result = func1()
print(result) # <generator object func1 at 0x00000269142097B0>
2.3 控制生成器产生数据的个数和值
- 一个生成器产生的数据的个数和值由创建生成器调用的那个函数的函数体在执行的时候会遇到几次yield以及yield后面的值来决定
- 个数:由遇到的yield的次数决定
- 值:由yield后面的数据决定
def create1():
yield 100
yield 200
yield 300
gen2 = create1()
# print(list(gen2)) # [100, 200, 300]
print(next(gen2)) # 100
print(next(gen2)) # 200
print(next(gen2)) # 300
# print(next(gen2)) # StopIteration
def create2():
x = 0
while True:
yield x
x += 1
gen2 = create2()
print(next(create2())) # 0
print(next(create2())) # 0
print('--------------------优雅转场,华丽分割-------------------')
for _ in range(100):
print(next(gen2))
print('--------------------优雅转场,华丽分割-------------------')
# 练习:写一个生成器可以创建某个python班级的学生的学号,学号的范围是:python0001~python1000
def create_stu_id():
for x in range(1, 1001):
yield 'python'+str(x).rjust(4, '0')
# yield f'python{x:0>4}'
gen3 = create_stu_id() # 用一个变量保存起来,不用每次调用都重新创建一个生成器
print(next(gen3)) # python0001
print(next(gen3)) # python0002
print('--------------------优雅转场,华丽分割-------------------')
for _ in range(10):
print(next(gen3)) # python0003~python0012
# print(next(create_stu_id())) python0001
# print(next(create_stu_id())) python0001 每次调用就创建一个生成器
2.4 生成器创建数据的原理
每次获取生成器的数据的时候,就会去执行创建这个生成器的函数体,但是每次执行都只会执行到yield就停下来
def func2():
print('=======')
yield 100
print('+++++++')
yield 200
gen4 = func2()
print('1->', next(gen4))
print('2->', next(gen4))
三. 装饰器
3.1 认识装饰器 - 给已经定义好的函数添加功能的工具
装饰器就是一个函数,这个函数既是实参高阶函数,又是返回值高阶函数
3.2 给函数添加功能
# 练习:给函数添加功能,统计函数的执行时间
# 方法1:直接修改原函数
import time
# def hello():
# # start = time.time()
# print('hello world!')
# # end = time.time()
# # print(f'总时间:{end - start}')
#
# hello()
# def factorial(n):
# start = time.time()
# s = 1
# for x in range(1, n+1):
# s *= x
# print(s)
# end = time.time()
# print(f'总时间:{end - start}')
#
# factorial(10)
print('--------------------优雅转场,华丽分割-------------------')
# 方法2:
# def total_time(fn, *args, **kwargs):
# start = time.time()
# fn(*args, **kwargs)
# end = time.time()
# print(f'总时间:{end - start}')
#
# total_time(hello) # 不写()
# total_time(factorial, 5)
# 方法3:
def total_time(fn):
def new_fn(*args, **kwargs):
start = time.time()
result = fn(*args, **kwargs)
end = time.time()
print(f'总时间:{end - start}')
return result
return new_fn
@total_time
def hello():
print('hello world!')
@total_time
def factorial(n):
s = 1
for x in range(1, n+1):
s *= x
print(s)
hello()
factorial(5)
四. 无参装饰器
4.1 无参装饰器语法
-
语法:
def 装饰器名(原函数):
def 添加完功能的新函数(*args, **kwargs):
调用原函数
添加新功能
return 添加完功能的新函数 -
语法细化:
def 装饰器名(f):
def new_f(*args, **kwargs):
result = f(*args, **kwargs)
新增功能
return result
return new_f -
装饰器名 - 根据新增的功能来命名
# 练习1:写一个装饰器,在函数调用之前打印'热烈欢迎'
def add_tag(fn):
def new_fn(*args, **kwargs):
print('热烈欢迎')
result = fn(*args, **kwargs)
return result
return new_fn
@add_tag # hello = add_tag(hello)
def hello():
print('hello world!')
@add_tag
def sum(num1, num2):
print(num1 + num2)
hello()
sum(10, 20)
print('--------------------优雅转场,华丽分割-------------------')
# 练习2:写一个装饰器在函数调用结束的时候打印'====end===='
def end_print(fn):
def new_fn(*args, **kwargs):
result = fn(*args, **kwargs)
print('====end====')
return result
return new_fn
@end_print
def haha():
print('hahaha')
haha()
print('--------------------优雅转场,华丽分割-------------------')
# 练习3:写一个装饰器将返回值是数字的函数的返回值变成原来返回值的100倍。 3 -> 300; 'abc' -> 'abc'; 1.23 -> 123
def change_num_return(fn):
def new_fn(*args, **kwargs):
result = fn(*args, **kwargs)
if type(result) in (int, float):
return result * 100
else:
return result
return new_fn
@change_num_return
def heihei():
return 10
@change_num_return
def xixi():
# print('xixi')
return 'abc'
print(heihei())
print(xixi())
五. 有参装饰器
-
有参装饰器语法细化:
def 装饰器名称(参数列表):
def 无参装饰器(f):
def new_fn(*args, **kwargs):
result = f(*args, **kwargs)
新增功能
return result
return new_fn
return 无参装饰器 -
参数列表 - 看实现装饰器新增功能需不需要额外的主句需要几个
# 写一个装饰器将返回值是数字的函数的返回值变成原来返回值的n倍。
def magnify(n):
def temp(f):
def new_f(*args, **kwargs):
result = f(*args, **kwargs)
if type(result) in (int, float):
return result * n
return result
return new_f
return temp
@magnify(5)
def sum3(num1, num2):
return num1 + num2
print(sum3(100, 200))