day11迭代器,生成器和闭包

迭代器

可迭代对象:直观理解就是能用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__________________

总结:若一个函数被多个装饰器所装饰,对于装饰器的外函数内的代码,会先按照离按数近的装饰器内的先执行,当外函数执行完之后则可以看作一个多层的嵌套函数,像是装饰器由离函数近到远的顺序内函数将原函数一层层包裹。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值