迭代器
可迭代对象:直观理解就是能用for循环进行迭代的对象就是可迭代对象。比如:字符串,列表,元祖,字典,集合等等
迭代器:是一个带状态的对象,他能在你调用next()
方法的时候返回容器中的下一个值,任何实现了__iter__
和__next__()
方法的对象都是迭代器,__iter__
返回迭代器自身,__next__
返回容器中的下一个值,如果容器中没有更多元素了,则抛出StopIteration异常。
可迭代对象通过自身的__iter__
方法返回一个迭代器,通过迭代器的__next__
方法来一个个取值
迭代器的对应方法(其中必定有__iter__
和__next__
)
li=[1,2,3]
print(dir(li.__iter__()))
#['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__length_hint__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__']
通过__next__
遍历取值(如果超出个数,则会抛出StopIteration异常)
li=[1,2,3]
liter=li.__iter__()
print(liter.__next__())
print(liter.__next__())
print(liter.__next__())
#1
#2
#3
可迭代对象测试 使用
isinstance()来判断
collections.abc
from collections.abc import Iterable
print(isinstance([],Iterable))
print(isinstance(str(),Iterable))
print(isinstance(set(),Iterable))
print(isinstance('',Iterable))
print(isinstance(15,Iterable))
#True
#True
#True
#True
#False
自定义一个类,其可以容纳数据,测试其的可迭代性
from collections.abc import Iterable
class test:
def __init__(self,*args):
self.values=list(args)
def add(self,value):
self.values.append(value)
def __iter__(self):
return self.values.__iter__() #实际上是调用返回列表的迭代器
test1=test(1,2,3,4,5)
test1.add(6)
print(isinstance(test1,Iterable))
for i in test1:
print(i)
#True
#1
#2
#3
#4
#5
#6
构建一个迭代器返回斐波那契数列
class FibIterator(object):
"""斐波那契数列生成迭代器"""
def __init__(self,max):
self.max=max
self.n=0
self.start=0
self.start2=1
def __iter__(self):
return self
def __next__(self):
if self.n<self.max :
a=self.start
self.start=self.start2
self.start2+=a
self.n+=1
return a
else:
raise StopIteration
fib=FibIterator(10)
for i in fib:
print(i,end=" ")
#0 1 1 2 3 5 8 13 21 34
生成器
利用迭代器我们可以在每次迭代获取数据时(__next__
方法)按照特定的规律进行生成。但是我们在实现一个迭代器时,关于当前迭代的状态需要自行记录,从而才能凭借当前的状态生成下一个数据。为了能纪律当前状态并配合next()函数进行迭代使用,可以选择更简便的语法→生成器
生成器是一种特殊的迭代器,语法更加优雅。
生成器函数
在函数中如果出现了yield关键字,那么该函数就不再是一个普通函数而是生成器函数
next和yield进行匹配。如果遇到return,return后的语句不会再执行,直接抛出StopIteration
-
close()
- 受从关闭生成器,后面调用会直接引起StopIteration异常
-
send()
- send方法有一个参数,该参数指定的是上一次被挂起的yield语句的返回值
def MyGenerator():
value = (yield 1)
print(value,"is value")
value = (yield 2)
print(value,"is value")
gen = MyGenerator()
print(gen.__next__())
print(gen.send(3))
print(gen.send(4))
#1
#3 is value #在上面引用到gen.send(2)时会把上一次调用yield关键字的返回值改变为参数3。即value = (yield 1)语句中本应值为1的value改为3,所以才有这样的输出,下同
#2
#4 is value
# print(gen.send(3))
#StopIteration
闭包
闭
- 封闭(函数中的函数)
包
- 包含(该内部函数对外部函数作用域而非全局作用域变量的引用)
闭包:
-
内部函数对外部函数作用域里的变量的引用
-
函数内的属性,都是有生命周期,都是在函数执行期间
-
闭包内的闭包函数私有化
由于作用域的问题,函数内的属性,都是有生命周期的,只有在函数执行期间才会考虑这段代码
只有调用foo()时,内部的print()及bar()才能存活。现在为了让foo()内的bar()存活,即当foo()函数关闭之后bar()依然存活:
把bar()函数的引用作为foo()函数的返回值
def foo():
a=10
def bar(num):
print(a+num)
return inner
test=foo() #调用foo()函数之后返回了一个inner的引用存在test中
test(22) #这里test()相当于是在调用inner()函数
#32
装饰器
例如:
@func1 #装饰器
def func():
print("aaa")
存在的意义:
- 不影响原有函数的功能
- 可以添加新的功能
一般常见的。比如拿到第三方的API接口,第三方不允许修改这个接口。这个时候,装饰器就派上用场了。
装饰器本身也是一个函数,作用是为现有存在的函数,在不改变函数的基础上,增加一些功能或者装饰
它是以闭包的形式去实现的。
在使用装饰器函数时,在被装饰的函数的前一行,使用**@装饰函数名**形式来进行装饰
下面的func1函数就是最原始的装饰器,它的参数是一个函数,然后返回值也是一个函数。
其中作为参数的这个函数func()就在返回函数inner()的内部执行。然后在函数func()前面加上@func1,
func()函数就相当于被注入了计时功能,现在只要调用func(),它就已经变身为“新的功能更多”的函数了
import time
def func1(func):
def inner():
time1=time.time()
func()
time2=time.time()
execution_time = (time2 - time1)*1000
print("time is %d ms" % execution_time)
return inner
@func1
def func():
print("aaa")
if __name__ == '__main__':
func()
#aaa
#time is 0 ms
万能装饰器
根据被装饰函数得定义不同,分出了四种形式。
能不能实现一种,适用于任何形式函数定义得装饰器。
def func1(func):
def inner(*args,**kwargs):
print("start")
print(func(*args,**kwargs))
print("end")
return inner
@func1
def func(x,y):
return x+y
@func1
def func2():
return "asd"
if __name__ == '__main__':
func(5,8)
func2()
#start
#13
#end
#start
#asd
#end
函数被多个装饰器所装饰
一个函数在使用时,可能并不能仅仅通过过一个装饰器达到预期效果。所以需要多个装饰器来进行装饰。
def func1(func):
print("out11".center(40,'_')) #第三步
def inner(*args,**kwargs):
print("in11".center(40, '_')) #第五步
func(*args,**kwargs)
print("in12".center(40, '_')) #第九步
print("out12".center(40, '_')) #第四步
return inner
def func2(func):
print("out21".center(40, '_')) #第一步
def inner(*args,**kwargs):
print("in21".center(40, '_')) #第六步
func(*args,**kwargs)
print("in22".center(40, '_')) #第八步
print("out22".center(40, '_')) #第二步
return inner
@func1
@func2
def func():
print("test") #第七步
if __name__ == '__main__':
func()
#_________________out21__________________
#_________________out22__________________
#_________________out11__________________
#_________________out12__________________
#__________________in11__________________
#__________________in21__________________
#test
#__________________in22__________________
#__________________in12__________________
总结:若一个函数被多个装饰器所装饰,对于装饰器的外函数内的代码,会先按照离按数近的装饰器内的先执行,当外函数执行完之后则可以看作一个多层的嵌套函数,像是装饰器由离函数近到远的顺序内函数将原函数一层层包裹。