小常识,大应战!本文正在参加“程序员必备小常识”创造活动。

大家好,我是一碗周,一个不想被喝(内卷)的前端。假如写的文章有幸能够得到你的喜爱,万分有幸~

生成器

现在能够经过生成器来直接创建一个列表,可是由于内存的约束,列表的容量肯定是有限的,假如咱们需求一个包含几百个元素的列表,可是每次拜访的时候只拜访其中的几个,那剩余的元素不运用就很糟蹋内存空间。

这个时候生成器Generator)就起到了效果,他是依照某种算法不断生成新的数据,直到满意某一个指定的条件结束

得到生成式的方法有如下几种:

  1. 经过列表生成式来得到生成器,示例代码如下:

    g = (x for x in range(10))  # 将列表生成列的[]改动成为()
    # 打印其类型
    print(type(g))  # <class 'generator'>
    # 调用其元素
    print(g.__next__())  # 0
    print(g.__next__())  # 1
    print(g.__next__())  # 2
    print(g.__next__())  # 3
    print(g.__next__())  # 4
    # 运用.__next__的方法调用
    print(next(g))  # 5
    print(next(g))  # 6
    print(next(g))  # 7
    print(next(g))  # 8
    print(next(g))  # 9
    # 运用next()的办法调用
    print(next(g))  # 当数据调用不到时会报出错误 StopIteration
    

    需求多少调用多少,不调用的不会生成,也就不会占用内存空间,能够运用循环结构来依照需求来调用

    g = (x for x in range(10))  # 将列表生成列的[]改动成为()
    skip = True  # 判别条件
    count = 0  # 调用次数
    while skip:
        count += 1  # 循环一次+1
        print(next(g))
        if count > 9:
            break  # 跳出循环
    
  2. 运用函数借助yield关键字来完成一个生成器,生成斐波那契数列的前20个数,示例代码如下:

    def fun(length):
        a, b = 0, 1
        for _ in range(length):
            a, b = b, a + b
            yield a
    fib = fun(20)
    print(type(fib))  # <class 'generator'>  # 打印类型
    count = 0
    while count < 20:
        # 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765
        print(next(fib), "", end="")
        count += 1
    

    流程如下:

    在履行过程中,遇到yield关键字就会暂停履行,下次调用则持续从上次暂停的位置持续履行,因为是一个循环语句,所有会直接跳到for语句

    假如在调用yield,需求给它传值,就要运用.send()办法了。示例代码如下:

    def fun(num):
        n = 0
        for i in range(num + 1):
            n += i
            ret = yield n
            print(f"这是+到{ret}的第{i + 1} 次")
    g = fun(3)
    print(g.send(None))
    print(g.send('3'))
    print(g.send('3'))
    print(g.send('3'))
    '''
    ---输出成果---
    这是+到 3 的第 1 次
    1
    这是+到 3 的第 2 次
    3
    这是+到 3 的第 3 次
    6
    '''
    

    send的加入能够使生成器更加灵敏,可是需求注意的是第一次调用生成器的send()办法时,参数只能为None,否则会抛出异常。当然也能够在调用send()办法之前先调用一次next()办法,目的是让生成器先进入yield表达式。

迭代器与可迭代的生成器

可迭代的目标有生成器、元组、列表、调集、字典和字符串等

经过collectionsIterable函数结合isinstance(object, classinfo)来判别一个目标时不是可迭代的目标

迭代是拜访调集元素的一种方法。迭代器是一个能够记住遍历的位置的目标。迭代器目标从调集的第一个元素开始拜访,直到所有的元素被拜访完结束。迭代器只能往前不会撤退。很生成器也是迭代器。

能够被next ()函数调用并不断返回下一个值的目标称为迭代器: Iterator ,能够运用isinstance()判别一个目标是否是Iterator目标:

注意:可迭代的不必定是生成器,可是生成器必定第可迭代的。

把元组、列表、调集、字典和字符串等Iterable变成Iterator能够运用iter()函数

IterableIterator****的区别Iterable是能够作为for循环目标的总称;而Iterator目标需求被next()函数调用才不断返回下一个数据,直到没有数据时抛出StopIteration错误,而在这之前是不会知道其长度的,所以Iterator的计算是慵懒的,只有next()函数叫他才会返回成果,Iterator乃至能够表明一个无限大的数据流,例如全体自然数。

from collections.abc import Iterable, Iterator
a = [1, 2, 3]
b = {1, 2, 3}
c = (1, 2, 3)
d = "123"
e = 123
f = (x for x in range(5))
# 打印数据类型
print(type(a))  # <class 'list'>
print(type(b))  # <class 'set'>
print(type(c))  # <class 'tuple'>
print(type(d))  # <class 'str'>
print(type(e))  # <class 'int'>
print(type(f))  # <class 'generator'>
print("-" * 20)
# 打印是否为可迭代目标
print(isinstance(a, Iterable))  # True
print(isinstance(b, Iterable))  # True
print(isinstance(c, Iterable))  # True
print(isinstance(d, Iterable))  # True
print(isinstance(e, Iterable))  # False
print(isinstance(f, Iterable))  # True
print("-" * 20)
# 除了字符串都是可迭代目标
# 打印是否是迭代器
print(isinstance(a, Iterator))  # False
print(isinstance(b, Iterator))  # False
print(isinstance(c, Iterator))  # False
print(isinstance(d, Iterator))  # False
print(isinstance(f, Iterator))  # True
# 只有f(生成器)是迭代器
print("-" * 20)
# 经过iter()将可迭代转换为迭代器
print(isinstance(iter(a), Iterator))  # True
print(isinstance(iter(b), Iterator))  # True
print(isinstance(iter(c), Iterator))  # True
print(isinstance(iter(d), Iterator))  # True