Python迭代器与生成器
迭代器 Iterator
1.什么是迭代器
- 迭代器是访问可迭代对象的工具
- 迭代器是指用 iter(obj) 函数返回的对象(实例)
- 迭代器可以用next(it)函数获取可迭代对象的数据
2.迭代器函数iter和next
函数 | 说明 |
---|---|
iter(iterable) | 从可迭代对象中返回一个迭代器,iterable必须是能提供一个迭代器的对象 |
next(iterator) | 从迭代器iterator中获取下一个记录,如果无法获取一下条记录,则触发 StopIteration 异常 |
3.迭代器说明
- 迭代器只能往前取值,不会后退
- 用iter函数可以返回一个可迭代对象的迭代器
4.迭代器示例
python
"""
迭代器
"""
#可迭代对象
L = list(range(10))
it = iter(L)
print(iter(L))
print(next(it)) # 0
print(next(it)) # 1
print(next(it)) # 2
print(next(it)) # 3超过索引范围进行报错
while True:
try:
print(next(it)) # 4 5 6 7 8 9
except:
print("迭代结束")
break
5.迭代器的用途
1.迭代器对象能用next函数获取下一个元素
生成器
1.生成器是在程序运行时生成数据,与容器不同,它通常不会在内存中保留大量的数据,而是现用现生成。
- yield 是一个关键字,用于定义生成器函数,生成器函数是一种特殊的函数,可以在迭代过程中逐步产生值,而不是一次性返回所有结果。
- 跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
- 每次使用 yield 语句生产一个值后,函数都将暂停执行,等待被重新唤醒。
- yield 语句相比于 return 语句,差别就在于 yield 语句返回的是可迭代对象,而 return 返回的为不可迭代对象。
- 然后,每次调用生成器的 next() 方法或使用 for 循环进行迭代时,函数会从上次暂停的地方继续执行,直到再次遇到 yield 语句。
生成器可以用算法动态的生成数据
2.生成器有两种
- 生成器函数
- 生成器表达式
生成器函数
1.含有yield 语句的函数是生成器函数,此函数调用回返回一个生成器对象,生成器也是可迭代对象
2.yield 语句的语法
yield 表达式
3.生成器函数示例
python
"""
生成器对象 生成器和迭代器一样可以配套for使用
"""
def myange(stop):
i = 0
while i<stop: # 步骤1
yield i # 调用一次产生一次数据 步骤2
i +=1
# print(myange(10)) # 无内容输出
for x in myange(10):
print(x) # 步骤3
print(next(myange(10))) # 可以访问生成器中的数据,一次next生成一个数据
生成器表达式
1.语法:
( 表达式 for 变量 in 可迭代对象 [if 真值表达式])
[] 内容代表可以省略
2.作用:用推导式的形式创建一个生成器
3.示例
python
re1 = [x ** 2 for x in range(1, 5)] # 列表解析(列表推导式)[1, 4, 9, 16]
print(re1) # [1, 4, 9, 16]
re2 = (x ** 2 for x in range(1, 5)) # 生成器表达式 <generator object <genexpr> at 0x7f41dcd30a40>
print(re2) # <generator object <genexpr> at 0x000001BEF95D3780> 不被调用,所有不被执行
for y in (x ** 2 for x in range(1, 5)): # 需要和for循环搭配使其生效
print(y) #2,4,9,16
python 函数式编程
1.定义:用一系列函数解决问题。
- 函数可以赋值给变量,赋值后变量绑定函数。
- 允许将函数作为参数传入另一个函数。
- 允许函数返回一个函数。
函数作为参数
1.将核心逻辑传入方法体,使该方法的适用性更广。
2.示例
python
def func01():
print("func01执行")
# a = func01
# # print(a)
# a()
def func02():
print("func02执行")
# 通用
def func03(func):
print("func03执行")
func()
func03(func02)
func03(func01)
3.注释
(1)a = func01
:
- 变量
a
现在指向func01
函数对象。 a
不是函数的返回值,而是函数对象本身
(2)print(a)
:
- 打印
a
,输出<function func01 at 0x...>
,表示a
是一个函数对象,并显示其内存地址。
(3)赋值语句 a = func01
并不会执行 func01
函数,只是将函数对象赋值给 a
。调用 a()
或 func01()
才会执行函数代码。
4.示例
python
"""
函数编程 语法
"""
def fun01():
print("fun01函数执行了")
a = fun01
print(a) #变量存储的是函数内存地址 <function fun01 at 0x0000019B9A87A200>存放函数的内存地址
def fun02(func):
print("fun02执行了")
func()
fun02(fun01) # 传入函数名称 fun02执行了 fun01函数执行了
"""
函数编程思想编程题
"""
list01 = list(range(100))
#需求:将大于5的数取出来
def find01():
for item in list01:
if item>5:
yield item
#需求:查找里表中所有的奇数
def find02():
for item in list01:
if item % 2 == 1:
yield item
"""
面向过程的思想
封装 分 把不同的点分割出来
"""
def conditon01(item):
return item > 5
def condition02(item):
return item % 2 == 1
"""
继承 -隔离的思想
"""
def find(func):
for item in list01:
if func(item):
yield item
"""
做- 多态
"""
for data in find(conditon01):
print(data) # 打印数据,因为item取出来的是数据
for data in find(condition02):
print(data)
5.总结
(1)什么时候使用函数式编程思想?
- 很多的逻辑或者说核心点是不变的,大多数就是一致的,这个时候我们就可以使用函数式编程思想,可以很好的去定位这个逻辑【函数 式编程思想相对于面向对象编程思想,它更接近于算法】。
(2)函数式编程思想替代了面向对象思想?
- 如果需求中存在多个逻辑变化点时,可以使用类来进行,因为面向对象中存在继承、重写。而函数式编程思想则是将变化点提取到函数 中,实现简单的逻辑。
6.练习
python
class Girl:
list_girl = []
def __init__(self,name,score,age,height):
self.name = name
self.score = score
self.age = age
self.height = height
# print(self)
Girl.list_girl.append(self)
girl01 = Girl("阿珂", 100, 23,160)
girl02 = Girl("苏荃", 92, 32,169)
girl03 = Girl("双儿", 90, 25,165)
girl04 = Girl("小郡主", 76, 22,167)
girl05 = Girl("方怡", 75, 27,168)
girl06 = Girl("建宁", 86, 25,164)
girl07 = Girl("曾柔", 67, 24,165)
# 需求:查找所有高于160的美女
# def fun01():
# for item in Girl.list_girl:
# if item.height > 160:
# yield item
#
# # 需求:颜值大于90的美女
# def fun02():
# for item in Girl.list_girl:
# if item.score > 90:
# yield item
"""
封装 找不同点
继承 找相同点
多态 实现不同目的
"""
# 封装 找不同点
def condition01(item):
return item.height > 160
def condition02(item):
return item.score > 90
def find(func):
for item in Girl.list_girl:
if func(item):
yield item
# def print_condition01():
for result in find(condition01):
print(result.name) #这个返回的是对象中的属性 苏荃 双儿 小郡主 方怡 建宁 曾柔
# def print_condition02():
for result1 in find(condition02):
print(result1)#这个返回的是一个对象 <__main__.Girl object at 0x00000218ADB1A6F0> <__main__.Girl object at 0x00000218ADB1A720>
lambda 表达式
1.定义:是一种匿名函数
2.作用:
- 作为参数传递时语法简洁,优雅,代码可读性强。
- 随时创建和销毁,减少程序耦合度。
3.语法
# 定义: 变量 = lambda 形参: 方法体 # 调用: 变量(实参)
4.说明
- 形参没有可以不填
- 方法体只能有一条语句,且不支持赋值语句。
python
# 1. 有参数有返回值
# def func01(a,b):
# return a > b
#
# print(func01(10,20))
func01 = lambda a,b:a > b
print(func01(10,20))
# 2. 无参数有返回值
# def func02():
# return "ok"
#
# print(func02())
func02 = lambda :"ok"
print(func02())
# 3. 无参数无返回值
# def func03():
# print("ok")
#
# func03()
func03 = lambda :print("ok")
func03()
# 4. 有参数无返回值
# def func03(a):
# print(a)
#
# func03(100)
func03 = lambda a:print(a)
func03(100)
# 5. lambda 不支持赋值语句
# def func05(iterable):
# iterable[0] = 100
#
# list01 = [1]
# func05(list01)
# print(list01)
# func05 = lambda iterable: iterable[0] = 100 报错
# 6. lambda 不支持多条语句
# def func06(a,b):
# print(a)
# print(b)
#
# func06(10,20)
# func06 = lambda a,b: print(a);print(b)
内置高阶函数
1.定义:将函数作为参数或返回值的函数。
2.常用:
(1)map(函数,可迭代对象)
- 使用可迭代对象中的每个元素调用函数,将返回值作为新可迭代对象元素;返回值为新可迭代对象。
(2)filter(函数,可迭代对象)
- 根据条件筛选可迭代对象中的元素,返回值为新可迭代对象。
(3)sorted(可迭代对象, key=函数, reverse=True)
- 排序,返回值为排序后的列表结果。
(4)max(可迭代对象, key = 函数)
- 根据函数获取可迭代对象的最大值。
(5)min(可迭代对象,key = 函数)
- 根据函数获取可迭代对象的最小值。
示例
python
"""
内置高阶函数
"""
class Girl:
list_girl = []
def __init__(self,name,score,age,height):
self.name = name
self.score = score
self.age = age
self.height = height
# print(self)
Girl.list_girl.append(self)
def __str__(self):
#必须以字符串的形式进行返回
return f"{self.name}-{self.score}-{self.age},{self.height}"
girl01 = Girl("阿珂", 100, 23,160)
girl02 = Girl("苏荃", 92, 32,169)
girl03 = Girl("双儿", 90, 25,165)
girl04 = Girl("小郡主", 76, 22,167)
girl05 = Girl("方怡", 75, 27,168)
girl06 = Girl("建宁", 86, 25,164)
girl07 = Girl("曾柔", 67, 24,165)
print(girl04)
#打印所有对象的名称
for element01 in map(lambda item:item.name,Girl.list_girl):
print(element01)
#获取所有颜值大于80的美女对象
for element02 in filter(lambda item:item.score > 80 ,Girl.list_girl):
print(element02) # 返回的迭代器
#获取年龄最大的美女对象
maxage=max(Girl.list_girl,key=lambda item:item.age)
print(maxage) # 返回的是符合最大值的对象
#对美女年龄进行排序 reverse默认是降序排列(False)
for element03 in sorted(Girl.list_girl,key=lambda item:item.score,reverse=True):
print(element03)
#美女中身高最矮的
minheight = min(Girl.list_girl,key=lambda item:item.height)
print(minheight)
print(map(lambda item:item.name,Girl.list_girl)) #<map object at 0x000001FF74FCB2B0>一个新的对了,里面包含姓名属性
print(filter(lambda item:item.score > 80 ,Girl.list_girl)) #<filter object at 0x000002713609BAF0>
print(max(Girl.list_girl,key=lambda item:item.age),min(Girl.list_girl,key=lambda item:item.height)) #苏荃-92-32,169 阿珂-100-23,160
print(sorted(Girl.list_girl,key=lambda item:item.score,reverse=True)) # [<__main__.Girl object at 0x000002713609B590>, <__main__.Girl object at 0x000002713609B5C0>, <__main__.Girl object at 0x000002713609BA10>, <__main__.Girl object at 0x000002713609BAA0>, <__main__.Girl object at 0x000002713609BA40>, <__main__.Girl object at 0x000002713609BA70>, <__main__.Girl object at 0x000002713609BAD0>]
函数作为返回值
闭包 closure
1.什么是闭包?
- 闭包是指引用了此函数外部嵌套函数的变量的函数 闭包就是能够读取其他函数内部变量的函数。只有函数内部的嵌套函数才能读取局部变量,所以闭包可以理解成"定义在一个函数内部的函数,同时这个函数又引用了外部的变量"。
- 在本质上,闭包是将内部嵌套函数和函数外部的执行环境绑定在一起的对象。
2.闭包必须满足以下三个条件
- 必须有一个内嵌函数
- 内嵌函数必须引用外部函数中变量
- 外部函数返回值必须是内嵌函数。
3.思考全局变量和局部变量的区别
-
全局变量:一直存在,谁都可以访问和修改
-
局部变量:只是在调用时存在,只能在函数内部进行访问和修改
4.闭包的优缺点 优点
- 逻辑连续,当闭包作为另一个函数调用参数时,避免脱离当前逻辑而单独编写额外逻辑。
- 方便调用上下文的局部变量。
- 加强封装性,是第2点的延伸,可以达到对变量的保护作用。
5.使用闭包的注意点(缺点)
- 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包
- 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
7.示例
python
"""
闭包
三大要素
1.具有内外函数 嵌套函数
2.内部函数要访问外部函数的变量
3.外部函数返回内部函数
"""
def fun01():
a = 1
def fun02():
print(a)
return fun02() #需要调用函数
re = fun01()
def fun01():
a = 1
def fun02():
print(a)
return fun02
re = fun01()
re()#需要调用函数
print(re)
python
"""
闭包的运用
逻辑运算
装饰器打基础
体现:外部函数执行过后,栈帧不释放,等待内部函数调用
"""
def give_money(money):
print(f"当前有{money}")
def child_buy(target,price):
nonlocal money
money -=price
print(f"我们购买了{target},孩子现在还有{money}")
return child_buy
re = give_money(200) #这里只传了一次惨,后面money值的更改是由于嵌套函数的操作
re("小汽车",50)
re("玩具手枪",50)
re("篮球",50) # 逻辑连续性,持续相减
8.示例
python
"""
闭包
"""
def fun01():
print("fun01执行了")
return "hello world"
def print_func_name(func):
def wrapper(*args,**kwargs):
#新功能
print(func.__name__)#__name__:获取函数名,内置属性
#旧功能
return func(*args,**kwargs)
return wrapper
re = print_func_name(fun01)
re()
python
"""
闭包
"""
def fun01():
print("fun01执行了")
return "hello world"
def fun02(func):
print("fun02执行了")
fun01()
def print_func_name(func):
def wrapper(*args,**kwargs):
def wrapper1(*args,**kwargs):
#新功能
print(1111)
print(func.__name__)#__name__:获取函数名,内置属性
#旧功能
return func(*args,**kwargs)
return wrapper1
return wrapper
# re = print_func_name(fun01)
# re1=re()
# re1()#正常运行,增加了内存的使用
re1 = print_func_name(fun02(fun01()))
re2=re1()
re2 #会先执行fun01,在执行fun02,但却不会执行装饰器中的代码了,虽然可以运行但脱离了装饰器的意义
装饰器 decorators(专业提高篇)
1.什么是装饰器:装饰器是一个函数,主要作用是来用包装另一个函数或类
2.装饰器的作用:在不修改被装饰的函数的源代码,不改变被装饰的函数的调用方式的情况下添加或改变原函数的功能。
3.函数装饰器的语法:
def 装饰器函数名(fn): 语句块 return 函数对象 @装饰器函数名 <换行> def 被装饰函数名(形参列表): 语句块
4.用函数装饰器替换原函数myfun
python
def mydeco(fn):
fn()
print("装饰器函数被调用了,并返回了fx")
def fx():
print("fx被调用了")
# return fn()
return fx
@ mydeco
def myfun():
print("函数myfun被调用")
myfun()
myfun()
5.当使用@mydeco
语法装饰myfun
函数时,实际上发生的是
myfun
函数作为参数传递给了mydeco
装饰器。- 在
mydeco
内部,首先调用了fn()
,即此时调用了myfun
函数,产生了输出:"函数myfun被调用"。 - 接着,打印了"装饰器函数被调用了,并返回了fx"。
- 然后,
mydeco
装饰器返回了新的函数fx
。
因此,此刻myfun
实际上被替换成了新的函数fx
。这样的行为正是Python装饰器的特性之一:装饰器可以修改函数的行为,甚至完全替换被装饰的函数。
基本装饰器
1.有参数的函数装饰器(在myfunc外加了一层)
python
def mydeco(fn):
def fx():
print("====这是myfunc被调用之前====")
ret = fn()
print("----这是myfunc被调用之后====")
return ret
return fx
@mydeco
def myfunc():
print("myfunc被调用.")
myfunc()
myfunc()
myfunc()
2.例
python
"""
装饰器
"""
# 装饰器名称
def print_func_name(func):
def wrapper(*args,**kwargs):
#新功能
print(func.__name__)#__name__:获取函数名,内置属性
#旧功能
return func(*args,**kwargs) # 需要在这里去真正的调用被装饰器,在被装饰器中不调用,就不会打装饰器的功能
return wrapper
#被装饰器
@print_func_name
def fun01():
print("fun01执行了")
return "hello world"
@print_func_name
def fun02():
print("fun02执行了")
print(1111)
fun02()
fun01()
"""
旧函数 统计值
新的函数、功能是打印总执行时间
"""
import time
#新函数
def all_time(func):
def wrapper(*args,**kwargs):#接收被装饰器的传参
#time.time()获得当前的时间
start_time = time.time()
result = func(*args,**kwargs)#运行被装饰器的时间,如果有参数,那么就要写上星号变量来接收
#获得结束时间
end_time = time.time()
print("执行时间:",end_time-start_time)
return result
return wrapper
#旧函数
@all_time
def fun01():
sum_value = 0
for i in range(100000000):
sum_value +=i
return sum_value
fun01()
@all_time
def fun02(n):
sum_value = 0
for i in range(n):
sum_value += i
return sum_value
fun02(100000)
带参数的装饰器
python
def repeat(num):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(num):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3) # 应用装饰器,重复执行下面的函数3次
def greet(name):
print(f"Hello, {name}!")
greet("Alice") # 调用被装饰的函数
repeat
是一个接受参数的装饰器工厂函数,它返回一个装饰器。decorator
是真正的装饰器,它接受一个函数func
作为参数。wrapper
函数重复执行被装饰的函数num
次。- 使用
@repeat(3)
应用装饰器,使greet
函数被执行3次。
注意:带参数的装饰器需要三层函数,def wrapper(args, kwargs) 传入的是被修饰的函数的参数。
装饰器链
python
def uppercase(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result.upper()
return wrapper
def exclamation(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result + "!"
return wrapper
@exclamation
@uppercase
def say_hello(name):
return f"Hello, {name}"
greeting = say_hello("Bob")
print(greeting) # 输出 "HELLO, BOB!"
1.具体的执行过程如下:
- 装饰器是从内到外依次应用的。在你的代码中,首先应用的是
@uppercase
,然后是@exclamation
。 @uppercase
装饰器会先包裹say_hello
函数,然后@exclamation
装饰器再包裹已经被@uppercase
包裹过的函数。
2.步骤详细如下:
(1)首先 @uppercase
包装 say_hello
函数:
- 调用
say_hello("Bob")
返回"Hello, Bob"
。 @uppercase
装饰器的wrapper
函数将结果转换为大写,变为"HELLO, BOB"
。
(2)然后 @exclamation
包装已经被 @uppercase
包装过的 say_hello
函数:
- 调用
wrapper
(即@uppercase
装饰器的wrapper
函数)返回"HELLO, BOB"
。 @exclamation
装饰器的wrapper
函数将结果加上一个感叹号,变为"HELLO, BOB!"
。
python
say_hello("Bob") -> "Hello, Bob"
"Hello, Bob" -> @uppercase -> "HELLO, BOB"
"HELLO, BOB" -> @exclamation -> "HELLO, BOB!"
类装饰器
python
class MyDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("Something is happening before the function is called.")
result = self.func(*args, **kwargs)
print("Something is happening after the function is called.")
return result
@MyDecorator # 应用类装饰器
def say_hello(name):
print(f"Hello, {name}!")
say_hello("Charlie") # 调用被装饰的函数
MyDecorator
是一个类装饰器,它接受一个函数func
作为参数并在__call__
方法中执行额外操作。- 使用
@MyDecorator
应用类装饰器,它将包装say_hello
方法,使其在调用前后执行额外操作。 - 与基本装饰器类似