python面试——迭代器,生成器,协程,装饰器

python面试——迭代器,生成器,协程,装饰器

迭代器

生成器是迭代器的一种。从迭代器开始说起。

可迭代协议:含iter()方法。且可迭代对象中的iter()方法返回的是一个对应的迭代器。(如list对应的迭代器就是list_iterator)
迭代器协议:
-含iter()方法。且方法返回的iterator对象本身
-含next()方法。每当next()方法被调用,返回下一个值,直到没有值可以访问,这个时候会抛出stopinteration的异常

查看python list内置类的源码可以发现它实现了iter()函数,所以list是一个可迭代对象,还有dict,str,set等等
迭代器与可迭代对象不同的是,迭代器对象不仅需要实现iter()方法,它还需要实现next()方法,即迭代器协议,事实上任何实现了iter()和next()方法的类对象都可以是迭代器对象。
此外迭代器含有两个基本的方法iter()和next(), iter()方法的作用是返回一个迭代器对象,当我们使用迭代器的next()方法显式获取元素的时候,迭代器对象会返回当前游标所指向的元素,并且向后移动游标位置,类似于C语言中的指针。如果没有元素可以获取,迭代器会抛出StopIteration异常,其实我们使用for…in…语句遍历迭代器元素的时候,for循环自动帮我们捕获了StopIteration异常。

迭代对象和可迭代对象:
迭代器对象遍历元素时消耗型的,遍历结束之后,迭代器中的元素集为空,这类似于队列的出队操作,
但实际上的原因是内存指针指向最后一个元素的内存地址后再继续向后移动指针就没有更多的元素,
所以迭代器是一个一次性产品,如果想重复使用,就需要使用list()函数将迭代器转换为一个可迭代对象。
迭代器对象和可迭代器对象中:可迭代对象在生成时将所有元素存入内存中,
然后迭代器对象只存储可迭代对象的第一个元素的地址,在遍历元素的时候,
next()函数会移动内存指针,读取下一个元素,
迭代器极大地节省了内存
import sys
#可以直观看出iterator object 与iterator之间区别
a = [i for i in range(1, 10000000)]
print('The size of list a is', sys.getsizeof(a))
b = iter(a)
print('The size of iterator object b is', sys.getsizeof(b))

生成器

列表生成器:

Info = [0,1,2,3,4,5,6,7,8,9]
A = [i+1 for I in range(10)]
Print(a)

通过列表生成器,我们可以直接创建一个列表,但是,受到内存限制,列表容量肯定是有限的,而且创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢? 这样就不必创建完整的list,从而节省大量的空间,在python中,这种一边循环一边计算的机制,称为生成器:generator
生成器是一个特殊的程序,可以被用作控制循环的迭代行为,python中生成器是迭代器的一种,使用yield返回值函数,每次调用yield会暂停,而可以使用next()函数和send()函数恢复生成器。
yield主要有两个功能:1:定位2、返回值(这个返回值相当去return)
生成器类似于返回值为数组的一个函数,这个函数可以接受参数,可以被调用,但是不同于一般的函数会一次性包括了所有数值的数组,生成器一次只能产生一个值,这样消耗的内存数量将大大减小,而且允许调用函数可以很快的处理前几个返回值,因此生成器看起来像是一个函数,但是表现得却像是迭代器。

Lis = [x*x for x in range(10) ]
Generator_ex = (x*x for x in range(10))
Print(next(Generator_ex))
import time
def consumer(name):
    print("%s 准备学习啦!" %name)
    while True:
       lesson = yield
       print("开始[%s]了,[%s]老师来讲课了!" %(lesson,name))
def producer(name):
    c = consumer('A')
    c2 = consumer('B')
    c.__next__()
    c2.__next__()
    print("同学们开始上课 了!")
    for i in range(10):
        time.sleep(1)
        print("到了两个同学!")
        c.send(i)
        c2.send(i)
yield b功能是:每次执行到有yield的时候,会返回yield后面b的值给函数并且函数会暂停,直到下次调用或迭代终止;
def fib(times): #times表示打印斐波拉契数列的前times位。
    n = 0
    a,b = 0,1
    while n<times:
        yield b  
        a,b = b,a+b
        n+=1
    return 'done'
 
print(fib(10))  #<generator object fib at 0x000001659333A3B8>

生成器函数:也是用def定义的,利用关键字yield一次性返回一个结果,阻塞,重新开始
生成器表达式:返回一个对象,这个对象只有在需要的时候才产生结果
为什么叫生成器函数?因为它随着时间的推移生成了一个数值队列。一般的函数在执行完毕之后会返回一个值然后退出,但是生成器函数会自动挂起,然后重新拾起急需执行,他会利用yield关键字关起函数,给调用者返回一个值,同时保留了当前的足够多的状态,可以使函数继续执行,生成器和迭代协议是密切相关的,迭代器都有一个__next__()__成员方法,这个方法要么返回迭代的下一项,要买引起异常结束迭代。

#函数有了yield之后,函数名+()就变成了生成器
#return在生成器中代表生成器的中止,直接报错
#next的作用是唤醒并继续执行
#send的作用是唤醒并继续执行,发送一个信息到生成器内部

def create_counter(n):
    print("create_counter")
    while True:
        yield n
        print("increment n")
        n +=1
 
gen = create_counter(2)
print(gen)
print(next(gen))
print(next(gen))
 
结果:
<generator object create_counter at 0x0000023A1694A938>
create_counter
2
increment n
3
Process finished with exit code 0

生成器表达式来源于迭代和列表解析的组合,生成器和列表解析类似,但是它使用尖括号而不是方括号
lpf

一个迭代既可以被写成生成器函数,也可以被协程生成器表达式,均支持自动和手动迭代。
而且这些生成器只支持一个active迭代,也就是说生成器的迭代器就是生成器本身。

协程

https://blog.csdn.net/andybegin/article/details/77884645
这个博客中对于协程说的很清楚

装饰器

python装饰器(fuctional decorators)就是用于拓展原来函数功能的一种函数,目的是在不改变原函数名(或类名)的情况下,给函数增加新的功能。

这个函数的特殊之处在于它的返回值也是一个函数,这个函数是内嵌“原“”函数的函数。

参考链接 https://www.cnblogs.com/yuzhanhong/p/9180212.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值