Python迭代器、生成器、装饰器
2021/5/16 14:25:19
本文主要是介绍Python迭代器、生成器、装饰器,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
文章目录
- 1 迭代器
- 1.1 可迭代对象
- 1.2 迭代器
- 1.3 自己实现一个可迭代对象
- 2 生成器
- 2.1 生成器的实现方式
- 3 装饰器
- 3.1 闭包
- 3.2 使用例子详细说明闭包
- 3.3 深度解析闭包
- 3.4 初识装饰器
1 迭代器
python可以从可迭代对象中获取迭代器
1.1 可迭代对象
- 概念
可迭代对象是使用iter内置函数可以获取迭代器的对象,如果对象实现了能返回迭代器的__iter__方法,那么对象就是可迭代的。序列都可以迭代;实现了__getitem__方法,并且参数从零开始的索引,这种对象也可以迭代。
# 第一种方式判断对象是不是可迭代对象 print('__iter__' in dir(list)) print('__iter__' in dir(tuple)) print('__iter__' in dir(dict)) print('__iter__' in dir(set)) print('__iter__' in dir(str)) print('__iter__' in dir(int)) print('__iter__' in dir(bool)) print('__iter__' in dir([1,2,3])) # 输出 True True True True True False False True # 第二种方式判断对象是不是可迭代对象 from collections import Iterable print(isinstance('abc', Iterable)) print(isinstance({1, 2, 3}, Iterable)) print(isinstance(1, Iterable)) 输出如下: True True False
1.2 迭代器
通过内置函数iter(iteratable) 返回可迭代对象的迭代器
next(iterator) 返回可迭代对象的下一个元素或者抛出StopIteration异常
it = iter([1,2,3,4]) next(it) > 1 next(it) > 2 next(it) > 3 next(it) > 4 next(it) > StopIteration
1.3 自己实现一个可迭代对象
class MyIter: def __init__(self): self.storage = [1,2,3] def __iter__(self): return self def __next__(self): try: return self.storage.pop() except Exception as e: return e mi = MyIter() # mi是一个可迭代对象,因为实现了__iter__方法 it = iter(mi) # it是一个迭代器 next(it) # 执行MyIter的__next__方法
2 生成器
生成器也是迭代器,但更加优雅。使用生成器,我们可以实现与迭代器相同的功能,但不必在类中编写iter()和next()函数
如果迭代器是人类,生成器就是人类中的一种,比如黄种人
2.1 生成器的实现方式
# 方式1 yield def gen(): yield 1 yield 2 yield 3 g = gen() # g是一个genenrator对象 next(g) > 1 next(g) > 2 next(g) > 3 next(g) > StopInteration # 方式2 推导式 li = [i*i for i in range(10000)] # 这是一句列表推导式,使用列表推导式会把0~9999的平方分别进行平方存储到这个列表中 # 生成器推导式 gen = (i*i for i in range(10000)) gen > <generator object <genexpr> at 0x000001FAE47B8CF0> next(gen) > 0 next(gen) > 1 next(gen) > 4 # 生成器与列表推导式相比可以节省内存空间,在你需要的时候获取值,而不是一次加载到内存中
3 装饰器
装饰器首先要学的是闭包
3.1 闭包
def out_func(data): def inner_func(): msg = "hello" print(f"{msg}-{data}") return inner_func
闭包的两个条件:
- 外部函数返回内部函数
- 内部函数使用外部函数作用域内的变量
3.2 使用例子详细说明闭包
# >符号开头的代表在命令行或者jupyter下执行命令 # 计算移动平均值的类 class Average(): def __init__(self): self.series = [] def __call__(self, new_value): self.series.append(new_value) total = sum(self.series) return total/len(self.series) > avg = Average() > avg(10) > 10 > avg(11) > 10.5 # 使用函数的形式 def make_average(): series = [] def average(new_value): series.append(new_value) total = sum(series) return total/len(series) return average > avg = make_average() # avg=average函数 > avg(10) # avg(10) series=[10] new_value=10 > 10 > avg(11) # avg(11) series=[10,11] new_value=11 > 10.5
3.3 深度解析闭包
- 自由变量
例子中的series列表就是一个自由变量,指未在本地作用域中绑定的变量,闭包延申到函数作用域之外,包含自由变量series的绑定
如图所示,闭包函数通过__code__的co_varnames返回闭包函数作用域内的所有变量,co_freevars返回不在闭包函数作用域内,在外层函数作用域内的变量,也就是“自由变量”
闭包函数的__closure__返回一个cell对象,cell对象是一个列表,获取列表的cell_contents属性可以拿到自由变量的值
- 自由变量如果是不可变数据类型
def make_average(): total=0 count=0 def average(new_value): total += new_value count += 1 return total/count return average avg = make_average() avg(10) > UnboundLocalError: local variable 'total' referenced before assignment # 先说一下解决方案,python3有一个关键字 nonlocal def make_average(): total=0 count=0 def average(new_value): nonlocal total,count total += new_value count += 1 return total/count return average avg = make_average() avg(10) > 10.0
当内部函数执行total+=new_value,相当于total被重新赋值,将自由变量变为局部变量,total就不是自由变量,就不会被保存到闭包中,所以报错
当使用series列表的时候,list.append(value),并没有改变列表的地址,利用了列表是可变对象的这个事实
nonlocal的作用就是声明这个不是局部变量,而是一个自由变量,这样才会被解释器重新保存到闭包中,对于python2中没有nonlocal这个关键字,只能利用可变对象做为闭包的自由变量。
3.4 初识装饰器
先了解闭包的原理,是学习装饰器的必要条件,话不多说,还是直接上代码,实践才是检验真理的唯一标准,哈哈哈
- 这是一个最基本的装饰器,例子来自于python3官方网站
def wrap(obj): return obj @wrap def say_hello(): return "hello world" say_hello() # 等同于warp(sayhello)() > "hello world" wrap(say_hello) #返回say_hello对象 > <function __main__.say_hello()> wrap(say_hello)() #执行say_hello > "hello world"
- 嵌套函数装饰器
# 嵌套函数的装饰器 def my_decorator(func): def wrapper(): print('wrapper of decorator') func() return wrapper def greet(): print('hello world') greet = my_decorator(greet) # greet = wrapper(wrapper是调用my_decoraor返回的函数对象),并且把greet放进闭包 greet() # 执行wrapper() 先输出print('wrapper of decorator'),在调用greet(),输出print('hello world') # 输出 >wrapper of decorator >hello world # @语法糖 def my_decorator(func): def wrapper(): print('wrapper of decorator') func() return wrapper @my_decorator #@是python的语法糖等同于my_decorator(greet) def greet(): print('hello world') greet() # 输出 >wrapper of decorator >hello world
- 带参数的嵌套函数装饰器
# 多层闭包 # repeat重复输出,num指重复输出次数 def repeat(num): def my_decorator(func): @functools.wraps(func)# 如果有这句 被装饰函数的__name__是被装饰函数本身的名字,如果没有,__name__不论被装饰函数是谁,都返回wrapper def wrapper(*args, **kwargs): for i in range(num): print('wrapper of decorator') func(*args, **kwargs) return wrapper return my_decorator @repeat(4) def greet(message): print(message) greet('hello world') # 输出: > wrapper of decorator > hello world > wrapper of decorator > hello world > wrapper of decorator > hello world > wrapper of decorator > hello world greet.__name__ #输出wrapper # functools.wrap会保留原函数的元信息
- 类装饰器
类装饰器主要依赖函数__call__ ,因此我们主要重写__call__即可。
每当调用一个类的实例,函数__call__就会执行一次。
class Count: def __init__(self, func): self.func = func self.num_calls = 0 def __call__(self, *args, **kwargs): self.num_calls += 1 print('num of calls is: {}'.format(self.num_calls)) return self.func(*args, **kwargs) @Count def example(): print("hello world") example() # 输出 num of calls is: 1 hello world example() # 输出 num of calls is: 2 hello world
- 嵌套装饰器
嵌套装饰器执行顺序从里到外
import functools def my_decorator1(func): @functools.wraps(func) def wrapper(*args, **kwargs): print('execute decorator1') func(*args, **kwargs) return wrapper def my_decorator2(func): @functools.wraps(func) def wrapper(*args, **kwargs): print('execute decorator2') func(*args, **kwargs) return wrapper @my_decorator1 @my_decorator2 def greet(message): print(message) greet('hello world') #相当于my_decorator1(my_decorator2(greet('hello world'))) # 输出 execute decorator1 execute decorator2 hello world
这篇关于Python迭代器、生成器、装饰器的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-25Python编程基础:变量与类型
- 2024-11-25Python编程基础与实践
- 2024-11-24Python编程基础详解
- 2024-11-21Python编程基础教程
- 2024-11-20Python编程基础与实践
- 2024-11-20Python编程基础与高级应用
- 2024-11-19Python 基础编程教程
- 2024-11-19Python基础入门教程
- 2024-11-17在FastAPI项目中添加一个生产级别的数据库——本地环境搭建指南
- 2024-11-16`PyMuPDF4LLM`:提取PDF数据的神器