day11-装饰器,迭代器和生成器

import time

1.什么是装饰器

“”"
装饰器的本质就是一个实参高阶函数和返回值高阶函数。
装饰器是用来给函数添加功能(在不修改原函数的基础上给函数添加功能)
“”"

func1就是返回值高阶函数

def func1():
def func2():
return ‘abc’
return func2

print(func1()) # <function func1..func2 at 0x10f3767a0>
print(func1()()) # abc

2.怎么给函数添加功能

print(’=======怎么给函数添加功能’)

方法一:直接修改原函数, 问题:给不同的函数添加相同功能的时候代码需要写多遍

def sum1(a=10, b=20):
time1 = time.time() # 获取当前时间
print(a+b)
time2 = time.time()
print(‘执行时间:’, time2-time1)

sum1(10, 20)

def factorial(n=5):
time1 = time.time()
sum1 = 1
for x in range(1, n+1):
sum1 *= x
print(sum1)
time2 = time.time()
print(‘执行时间:’, time2 - time1)

factorial(5)

方法二:实参高阶函数

print(’=实参高阶函数=’)

定义一个函数功能是统计一个函数的执行时间

def count_execution_time(func, *args, **kwargs):
# func= func4
time1 = time.time()
func(*args, **kwargs) # func4()
time2 = time.time()
print(‘执行时间:’, time2-time1)

def func2():
print(‘你好,世界!’)

func2()
count_execution_time(func2)

def func3(n=10):
print(n*2)

func3()
count_execution_time(func3)

def func4(m):
print(m*100)

func4(10)
count_execution_time(func4, 10)

def func5(m, n):
print(m*n)

count_execution_time(func5, 10, 40)
count_execution_time(func5, m=4, n=5)

解包:
def test(*args, **kwargs):
print(args, kwargs)
# agrs = (1, 2, 3) *agrs -> 1, 2, 3
print(*args) # print(1,2,3)

test(1, 2, 3)
test(a=10, b=20, c=30)
test(10, 20, a=2,x=3,y=5)

def test2(a, b, c):
print(f’a:{a}, b:{b}, c:{c}’)

test2(10, 20, 30) # a:10, b:20, c:30
nums = [10, 20, 30]
test2(*nums) # a:10, b:20, c:30

test2(a=10, b=20, c=30) # a:10, b:20, c:30
dict1 = {‘a’: 10, ‘c’: 30, ‘b’: 20}
test2(**dict1) # a:10, b:20, c:30

print(’======实参高阶函数改进=’)

方法三: 实参高阶函数改进

def count_execution_time(func):
def test(*args, **kwargs):
time1 = time.time()
# time.sleep(2)
func(*args, **kwargs)
time2 = time.time()
print(‘执行时间:’, time2-time1)
return test

def func4(m):
print(’=======’)

func4 = count_execution_time(func4)
func4(10)

print(’==装饰器=’)

方法四:装饰器

“”"
def 函数名1(func):
def test(*args, **kwargs):
func(*args, **kwargs)
添加新的功能
return test

说明:
函数名1 - 装饰器对应的函数名,也是装饰器的名字(根据需要添加的新功能命名)
func - func指向的就是需要添加新功能的函数
test - 指向的是已经添加完功能的新的函数
“”"
练习:写一个装饰器在原函数调用结束后打印’end’

def print_end(func):
def test(*args, **kwargs):
func(*args, **kwargs)
# 新功能
print(‘end’)
return test

@print_end
def func1():
print(’=====’)

@print_end
def sum2(a, b):
print(a+b)

func1()
sum2(10, 23)

“”"
def 函数名1(func):
def test(*args, **kwargs):
func(*args, **kwargs)
添加新的功能
return test
“”"

练习2:写一个装饰器在函数执行前打印 ‘start…’
print(’=================================’)

def add_start(func):
def test(*args, **kwargs):
print(‘start…’)
func(*args, **kwargs)
return test

@add_start
def func3():
print(‘你好吗?’)

func3()

定义一个装饰器,将函数的返回值转换成字符串
def switch_str(func):
def test(*args, **kwargs):
result = func(*args, **kwargs)
return str(result)
return test

@switch_str
def func11():
return 100

print(‘func11:’, func11()*3)

练习:写一个装饰器,可以给返回值是数字的函数添加新的功能,让原函数的结果保留2位小数
def two_deci(func):
def test(*args, **kwargs):
result = func(*args, **kwargs)
if type(result) in (int, float):
return float(f’{result:.2f}’)
return result

return test

@two_deci
def sum3(a, b):
return a+b

print(sum3(1.234, 5)+20)
print(sum3(10, 20))
print(sum3(‘abc’, ‘123’))

1.有参的装饰器

“”"
如果在实现装饰器新增的功能的时候需要额外的数据,那么就可以使用有参装饰器

def 装饰器名称(装饰器的参数列表):
def test1(func):
def test2(*args, **kwargs):
func(*args, **kwargs)
添加新的功能
return test2
return test1
“”"

练习: 写一个装饰器让函数的返回值保留N位小数(返回值是数字的时候)
def constraint_decimals(n):
def test1(func):
def test2(*args, **kwargs):
result = func(*args, **kwargs)
if type(result) == float:
nums = str(result).split(’.’)
return float(f’{nums[0]}.{nums[-1][0:n]}’)
return result
return test2
return test1

3.1 -> 3.100
3.1415926 ->

@constraint_decimals(3)
def sum1(a, b):
return a+b

print(sum1(3.1415926, 10) - 2)

练习: 写一个装饰器在函数结束后打印n个*
def add_star(n=5):
def test1(func):
def test2(*args, **kwargs):
result = func(args, *kwargs)
print(n
’)
return result

    return test2
return test1

@add_star()
def func1():
print(’========’)

func1()

@add_star(6)
def func2(n):
sum1 = 1
for x in range(1, n+1):
sum1 *= x
return sum1

result = func2(5)
print(result)

练习:写一个装饰器可以在原函数的返回值的基础上加上或者减去一个数(针对返回值是数字的函数)
def operation(symbol:str, num):
def test1(func):
def test2(*args, **kwargs):
result = func(*args, **kwargs)
if type(result) not in (int, float):
return result
if symbol == ‘+’:
return result + num
elif symbol == ‘-’:
return result - num
else:
return result
return test2
return test1

@operation(’+’, 50)
def sum1(a, b):
return a+b

print(sum1(10, 20))

1.什么是迭代器(iter)

“”"
1)迭代器的特点
迭代器是一种特殊容器: a.不能直接查看所有的元素(打印看不到任何元素;不能计算长度) b.如果要读取元素的值必须将这个元素从迭代器中取出来(取出来以后就再也放不回去,迭代器中就不再有这个元素了)

2)怎么创建迭代器
创建迭代器的方式有两种:
a.将其他序列转换成迭代器: iter(序列)
b.创建生成器(生成器的本质就是迭代器)
“”"
iter1 = iter([10, 20, 30, 40])
print(iter1) # <list_iterator object at 0x10d3921d0>
print(len(iter1)) # TypeError: object of type ‘list_iterator’ has no len()

iter2 = iter(‘hello’)
print(iter2) # <str_iterator object at 0x10de8edd0>

2.获取迭代器元素(查)

注意: 不管以任何方式获取到了迭代器的元素,这个元素在迭代器都不存在了

1)获取单个元素
next(迭代器) - 获取迭代器中最前面的一个元素

print(next(iter1)) # 10
print(next(iter1)) # 20
print(next(iter1)) # 30
print(next(iter1)) # 40
print(next(iter1)) # 报错, StopIteration
print(list(iter1)) # []

iter2 = iter(‘hello’)
print(list(iter2)) # [‘h’, ‘e’, ‘l’, ‘l’, ‘o’]
print(next(iter2)) # StopIteration

2)遍历

iter3 = iter([‘name’, ‘age’, ‘hello’, ‘world’])
for x in iter3:
print(x)
print(next(iter3)) # 遍历迭代器的时候已经将元素全部取出,所以没有办法再获取一个元素了

iter4 = iter(range(5))
next(iter4)
next(iter4)
for x in iter4:
print(f’x:{x}’)

1.生成器

“”"
生成器的本质就是迭代器;
生成器其实是能够产生多个数据的容器,而不是真正同时保存多个数据的容器
“”"

2.怎么创建生成器

“”"
调用带有yield关键字的函数就能得到一个生成器
“”"

调用普通函数:a.执行函数体 b.获取函数返回值

def func1():
print(‘abc’)
return 100

result = func1()
print(result) # 100

调用带有yield关键字的函数:a.不执行函数体 b.获取到的是生成器对象

def func2():
print(‘ABC’)
return 200
yield

result = func2()
print(result) # <generator object func2 at 0x1083f4150>

3.生成器怎么生产数据

“”"
a. 一个生成器能生产多少数据? - 看执行生成器对应的函数,在函数结束的时候能够遇到几次yield,就能生产多少个数据
b. 生产器生产的数据是哪些? - 看每次遇到 yield, yield后面的数据是什么,产生的数据就是什么
“”"

1)一个生成器能生产多少数据

def func3():
yield
print(’=====’)
yield
print(’+++++’)

gen1 = func3()
print(gen1) # <generator object func3 at 0x10e8931d0>
print(len(list(gen1))) # 2

def func4(n):
yield
if n % 2:
yield
print(‘end’)

gen2 = func4(4)
print(len(list(gen2))) # 1

gen3 = func4(5)
print(len(list(gen3))) # 2

2)生产器生产的数据是哪些?

def func5():
yield 10
yield 100

gen4 = func5()
print(list(gen4)) # [10, 100]

4.生成器产生数据的原理

“”"
调用函数创建生成器对象的时候不会执行函数体;当获取生成器中的元素的时候才会执行函数体。
获取第一个元素的时候从函数开始开始执行,执行遇到第一个yield就会停下来,并且将yield后面的数据作为这次获取到的元素,
下次获取元素的时候从上一次结束的位置接着往后执行函数体直到遇到下一个yield,并且将新的yield的数据作为新的元素,
以此类推
如果从上次结束的位置开始到函数结束都没有遇到yield那么这个生成器就不会再创建数据了,如果是next操作,这个时候会报错
“”"

def func6():
print(‘第一个:’)
yield 10
print(‘第二个:’)
yield 100
print(‘第三个:’)
yield ‘abc’

gen5 = func6()
print(next(gen5))
print(next(gen5))
for x in range(10):
print(x)

print(next(gen5))

def func7(n):
for m in range(n):
yield m*2

gen6 = func7(10)
print(next(gen6))
print(next(gen6))
for x in gen6:
print(f’x:{x}’)

练习:写一个学号的生成器,能够产生 stu0001 ~ stu9999 的学号
def create_study_num():
for x in range(1, 10000):
yield f’stu{str(x).zfill(4)}’

create_num_gen = create_study_num()
print(next(create_num_gen))
for _ in range(10):
print(next(create_num_gen))
print(next(create_num_gen))

注意: 每次调用函数的时候都是在创建新的生成器对象

print(next(create_study_num())) # stu0001
print(next(create_study_num())) # stu0001

create_num_gen2 = create_study_num()
print(create_num_gen, create_num_gen2)

def study_id(pre: str, width: int):
for x in range(1, 10**width):
yield pre+str(x).zfill(width)

create_num1 = study_id(‘python’, 2)
create_num2 = study_id(‘h5’, 3)
print(next(create_num1))
print(next(create_num1))
print(next(create_num2))
print(next(create_num2))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值