三大神器
1.迭代器(iter)
"""
迭代器是容器型数据类型(序列),迭代器无法直接获取所有元素,也不能统计元素个数。
获取迭代器中的元素的是会导致这个元素从迭代器中消失。(元素取一个就少一个)
"""
- 创建迭代器
# 创建迭代器只有两种方式:1)将其他序列转换成迭代器 2)创建生成器
iter1 = lier('abc')
print(iter1) # <str_iterator object at 0x000002556C238400>
iter2 = lter([10, 20, 30, 40]) # 列表可以 list
print(lter)
iter3 = lter([{'a': 10}, {'b': 20}]) # 字典也可以 dict
print(iter3)
- 获取迭代器中的元素
# 1) 获取单个元素:next(迭代器)
iter1 = iter('abc')
print(next(iter1)) # a
print(next(iter1)) # b
print(next(iter1)) # c
# print(next(iter1)) # StopIteration
# 2) 遍历
iter2 = iter([10, 29, 49, 12])
for x in iter:
print(f'x:{x}') # x:10 x:29 x:49 x:12
for x in iter:
print(f'x:{x}') # 上面已经取完,打印不出来
生成器
- 什么是生成器
"""
生成器从获取数据和保存特点来看,就是迭代器
生成器保存数据的本质并不保存数据本身,而是保存产生数据的算法。
"""
- 创建生成器
"""
调用带有yield关键字的函数就可以得到一个生成器
调用带有yield关键字的函数的时候不会执行函数体,也不会获取函数返回值,只是单纯的创建一个生成器
(函数中yield放在哪儿没有关系)
"""
def func1():
print('====')
return 100
yield
result = func1()
print(f'result:{result}, list(result)')
- 确定生成器的元素 - 生成器可以创造的数据
"""
一个生成器能产生多少个数据就看这个生成器对应的函数,执行完函数体会遇到几次yield
每次遇到yield的时候yield后面的数据就是产生的数据
"""
def func2():
print('++++')
yield 100
yield 200
yield 300
if 2 > 10:
yield 400
return
yield 500
result = func2()
print(next(result)) # 100
print(next(result)) # 200
print(next(result)) # 300
# print(next(result)) # StopIteration
- 生成器产生数据的原理
"""
当通过生成器对象获取元素(不管以什么样的方式获取)的时候,系统会自动执行生成器对应的函数,执行函数的时候不会直接将整个函数执行完,
而且每次在执行yield的时候就会停下来,并且将yield后面的数据作为结果返回。
下次再获取元素的是从上次结束的位置开始执行。
"""
def func3():
print('1111111')
yield 100
print('22222')
yield 200
peint('3333333')
yield 300
print('444444')
result = func3()
print(next(result))
print('!!!!!!!!!!!!')
print(next(result))
prin('~~~~~~~~~~~~~')
for x in result:
print(f'x:{x}')
def func4():
print(f'x:{x}')
result = func4()
print(next(result))
def func5():
yield 10
yield 20
yield 30
yield 40
print(next(func5())) # 10
print(next(func5())) # 10
result = func5() # 用变量保存起来
print(next(func5(result))) # 10
print(next(func5(result))) # 20
# 练习:写一个创建学生学号的生成器,要求产生的学号前缀是python,后面是指定范围的值。
# 26 ~ 56 -> python0026 ~ python0056
def nums1(subject='python', start=26, end=56):
for x in range(start, end+1):
yield f'{subject},{str(x).zfill(4)}'
装饰器
import time
- 什么是装饰器
"""
装饰器 = 实参高阶函数 + 返回值高阶函数 + 糖语法 (装饰器的本质是函数)
作用:给已经定义好的函数添加功能
"""
# 给函数添加功能解决办法一: 在需要添加功能的所有函数中添加新功能对应的代码
def func1():
start = time.time()
print('hello world!')
end = time.time()
print(f'函数执行时间: {end-start}')
func1()
def func2(a, b):
start = time.time()
print(a + b)
end = time.time()
print(f'函数执行时间: {end-start}')
func2(23, 45)
def total_time(fn):
def new_fn(*aegs, **kwargs):
start = time.time()
result = fn(*args, **kwatgs)
end = time.time()
print(f'函数执行时间:{end - start')
return result
return
@total_time
def func1():
print('hello world!')
# func1 = total_time(func1)
func1()
print('==============================')
@total_time
def func2(a, b):
print(a + b)
func2(10, 20)
- 无参装饰器的实现方法
"""
装饰器的工作原理:将需要添加功能的函数传给装饰器,装饰器创建一个保留原函数功能并且添加新功能的一个新的函数,
将添加完功能的新函数返回,最后用新的函数替换原来的函数。
装饰器的套路:
def 函数名1(参数1: function):
def 函数名2(*args, **kwargs):
添加新的功能
result = 参数1(*args, **kwargs)
return result
return 函数2
函数名1 - 装饰器功能对应的名字
参数1 - 类型是function, 指向需要添加功能的原函数,习惯命名成:fn
函数名2 - 指向添加完功能的新函数, 习惯命名成:new_fn
def 装饰器名(fn)
def new_fn(*args, **kwargs):
新功能
result = fn(*args, **kwargs) # 调用原函数
return result
return new_fn
"""
# 1.写一个装饰器在函数调用结束的是打印'end'
def add_end_message(fn):
def new_fn(*args, **kwarks):
result = fn(*args, **kwargs)
print('end')
return result
return new_fn
# 2.写一个装饰器将原函数的返回值加100
def add_100(fn):
def new_fn(*args, **kwargs):
result = fn(*args, **kwargs)
if type(result) in (int, float):
return result + 100
return result
return new_fn
# @add_end_message # 相当于:func3 = add_end_message(func3)
@add_100 # 相当于 func3 = add_100(func3)
def func3(num: int):
sum1 = 1
for x in range(1, num+1):
sum1 *= x
return sum1
# @add_end_message
@add_100
def func4():
print('你好,世界!')
print('===================1=====================')
x = func3(4)
print(x)
# print(func3(4))
print('===================2=====================')
print(func4())
# 练习: 写一个装饰器,将函数的返回变成字符串
# 100 -> '100'
# None -> 'None'
# False -> 'False'
def to_str(fn):
def new_fn(*args, **kwargs):
result = fn(*args, **kwsrga)
return = result
return new_fn
递归
- 递归函数
# 1.递归函数
# 在定义函数的时候调用函数本身,这种函数就是递归函数
# 理论上,循环能做的事情递归都可以做。(能循环实现就不要用递归)
# 注意:使用递归解决循环问题的时候,内存和cpu的消耗会随着循环次数的增加而不断增加
def fn():
print('hello')
fn()
- 使用递归的套路
"""
第一步:找临界值,在临界值的位置结束函数
第二步:找关系,找上一次循环结束的结果和当次循环结束的结果的关系(f(n))和f(n-1)的关系)
第三步:假设函数功能已经实现,通过关系用f(n-1)实现f(n)的功能
"""
# 1. 计算1+2+3+...+n
def sum1(n):
# 临界值
if n == 1:
return 1
# 关系: sum1(n) 和 sum1(n-1)
# sum1(n) = 1+2+3+...n-1+n
# sum1(n-1) = 1+2+3+...n-1
# sum1(n) = sum1(n-1) + n
return sum1(n-1) + n
print(sum1(100))
def sum2(n):
sum1 = 0
for x in range(101):
sum1 += 1
return sum1
print(sum2(100))
# 1, 1, 2, 3, 5, 8, 13,...
def num(n):
if n == 1 or n == 2:
return 1
return num(n-1) + num(n-2)
print(num(1))
# 2.打印下面的图形
"""
n = 3
*
**
***
n = 4
*
**
***
****
"""
def star(n):
if n == 1:
print('*')
return
star(n-1)
print('*'*n)
作业
- 为函数写一个装饰器,在函数执行之后输出 after
def nexus(ff):
def new_ff(*args, **kwargs):
result = ff(*args, **kwargs)
print('after')
return result
return new_ff
- 为函数写一个装饰器,把函数的返回值 乘2再返回值
def nexus1(ff):
def new_ff(*args, **kwargs):
result = ff(*args, **kwargs)
if type(result) in (int, float):
return result * 2
return result
return new_ff
- 写一个装饰器@tag要求满足如下功能:
def tag(ff):
def new_ff(*args, **kwargs):
result = ff(*args, *kwargs)
return f'<p>{result}</p>'
return new_ff
@tag
def render(text):
# 执行其他操作
return text
@tag
def render2():
return 'abc'
print(render('Hello')) # 打印出: <p>Hello</p>
print(render2()) # 打印出: <p>abc</p
-
写一个创建一副扑克牌的生成器。
-
使用递归函数画出以下图形:
# n = 5
# *****
# ****
# ***
# **
# *
#
# n = 4
# ****
# ***
# **
# *
def nums(n):
if n == 1:
print('*')
return
else:
print(n * '*')
return nums(n - 1)
print(nums(5))