Python迭代器、生成器、装饰器

Python迭代器、生成器、装饰器,第1张

概述文章目录1迭代器1.1可迭代对象1.2迭代器1.3自己实现一个可迭代对象2生成器2.1生成器的实现方式3装饰器3.1闭包3.2使用例子详细说明闭包3.3深度解析闭包3.4初识装饰器1迭代器python可以从可迭代对象中获取迭代器1.1可迭代对象概念可迭代对象是使用i

文章目录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]))# 输出TrueTrueTrueTrueTrueFalseFalseTrue# 第二种方式判断对象是不是可迭代对象from collections import Iterableprint(isinstance('abc', Iterable))print(isinstance({1, 2, 3}, Iterable))print(isinstance(1, Iterable))输出如下: TrueTrueFalse
1.2 迭代器

通过内置函数iter(iteratable) 返回可迭代对象的迭代器
next(iterator) 返回可迭代对象的下一个元素或者抛出stopiteration异常

it = iter([1,2,3,4])next(it)> 1next(it)> 2next(it)> 3next(it)> 4next(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 yIElddef gen():	yIEld 1	yIEld 2	yIEld 3 g = gen() # g是一个genenrator对象next(g)> 1next(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)> 1next(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 averageavg = make_average()avg(10)> UnboundLocalError: local variable 'total' referenced before assignment # 先说一下解决方案,python3有一个关键字 nonlocaldef make_average():    total=0    count=0    def average(new_value):    	nonlocal total,count        total += new_value        count += 1        return total/count    return averageavg = 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     @wrapdef 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 wrapperdef 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 worldgreet.__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)@Countdef example():    print("hello world")example()# 输出num of calls is: 1hello worldexample()# 输出num of calls is: 2hello world
嵌套装饰器
嵌套装饰器执行顺序从里到外
import functoolsdef my_decorator1(func):    @functools.wraps(func)    def wrapper(*args, **kwargs):        print('execute decorator1')        func(*args, **kwargs)    return wrapperdef my_decorator2(func):    @functools.wraps(func)    def wrapper(*args, **kwargs):        print('execute decorator2')        func(*args, **kwargs)    return wrapper@my_decorator1@my_decorator2def greet(message):    print(message)greet('hello world')  #相当于my_decorator1(my_decorator2(greet('hello world')))# 输出execute decorator1execute decorator2hello world
总结

以上是内存溢出为你收集整理的Python迭代器、生成器、装饰器全部内容,希望文章能够帮你解决Python迭代器、生成器、装饰器所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1186295.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-03
下一篇 2022-06-03

发表评论

登录后才能评论

评论列表(0条)

保存