• python之序列去重以及生成器、生成器函数、生成器表达式与迭代器浅谈


    首先要明确序列值类型是否可哈希,因为可哈希的值很简单就可以用 in /not in 写个生成器去判断,如果是不可哈希的就要去转换为可哈希的再用 in/not in 去判断

    原地不可变类型(可哈希):

    • 数字类型:int, float, decimal.Decimal, fractions.Fraction, complex
    • 字符串类型:str, bytes
    • tuple
    • frozenset
    • 布尔类型:True, False
    • None

    原地可变类型(不可哈希):

    • list
    • dict
    • set
    举例可哈希序列去重
    b=[1,2,3,1,2,5]
    def debque1(items):
        result=set()
        for item in items:
            if item not in result:
                yield item
                result.add(item)
    
    print(list(debque1(b))) #[1, 2, 3, 5]
    举例不可哈希序列去重
    a = [ {'x':1, 'y':2}, {'x':1, 'y':3}, {'x':1, 'y':2}, {'x':2, 'y':4}]
    def debque2(items,key=None):
        result=set()
        for item in items:
            val=item if key is None else key(item)
            if val not in result:
                yield item
                result.add(val)
    
    print(list(debque2(a,key=lambda item:(item["x"],item["y"]))))   # [{'x': 1, 'y': 2}, {'x': 1, 'y': 3}, {'x': 2, 'y': 4}]

    这方法利用了生成器,科普一下生成器

    如果列表元素可以按照某种算法推算出来,那我们就可以在循环的过程中不断推算出后续的元素,这样就不必创建完整的list,从而节省大量的空间,所以zai在Python中,就出现了这种一边循环一边计算的机制,称为生成器:generator

    生成器是迭代器的一种,使用yield返回值函数,每次调用yield会暂停,而可以使用next()函数和send()函数恢复生成器。

    要创建一个generator,有很多种方法,第一种方法很简单,只有把一个列表生成式的[]中括号改为()小括号,就创建一个generator

    # 列表生成式
    lis = [x*x for x in range(10)]
    print(lis)
    # 生成器
    generator_ex = (x*x for x in range(10))
    print(generator_ex)
     
    # 结果:
    # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    # <generator object <genexpr> at 0x000002A4CBF9EBA0>

    如果要一个个打印出来,可以通过next()函数获得generator的下一个返回值:

    但是一般不这么做,正确的方法是使用for循环,因为generator也是可迭代对象

      生成器函数:也是用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

     yield是一个类似return 的关键字,迭代一次遇到yield的时候就返回yield后面或者右面的值。而且下一次迭代的时候,从上一次迭代遇到的yield后面的代码开始执行

    ——生成器表达式

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

    >>> # 列表解析生成列表
    >>> [ x ** 3 for x in range(5)]
    [0, 1, 8, 27, 64]
    >>>
    >>> # 生成器表达式
    >>> (x ** 3 for x in range(5))
    <generator object <genexpr> at 0x000000000315F678>
    >>> # 两者之间转换
    >>> list(x ** 3 for x in range(5))
    [0, 1, 8, 27, 64]

    --迭代器(迭代就是循环)

    可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator

    可迭代对象有:

    一类是集合数据类型,如list,tuple,dict,set,str等

    一类是generator,包括生成器和带yield的generator function

    这些可以直接作用于for 循环的对象统称为可迭代对象:Iterable

    但是必须可以被next() 函数调用病不断返回下一个值! 的  可迭代对象,才是迭代器

    # 判断下列数据类型是可迭代对象or迭代器
    s='hello'     #字符串是可迭代对象,但不是迭代器
    l=[1,2,3,4]     #列表是可迭代对象,但不是迭代器
    t=(1,2,3)       #元组是可迭代对象,但不是迭代器
    d={'a':1}        #字典是可迭代对象,但不是迭代器
    set={1,2,3}     #集合是可迭代对象,但不是迭代器
    # *************************************
    f=open('test.txt') #文件是可迭代对象,是迭代器

    可以用isinstance 判断

    print(isinstance(s,Iterator))     #判断是不是迭代器
    print(isinstance(s,Iterable))       #判断是不是可迭代对象

    listdictstrIterable变成Iterator可以使用iter()函数

    >>> isinstance(iter([]), Iterator)
    True
    >>> isinstance(iter('abc'), Iterator)
    True

    Python3的for循环本质上就是通过不断调用next()函数实现的,例如:

    for x in [1, 2, 3, 4, 5]:
        pass

    实际上完全等价于

    # 首先获得Iterator对象:
    it = iter([1, 2, 3, 4, 5])
    # 循环:
    while True:
        try:
            # 获得下一个值:
            x = next(it)
        except StopIteration:
            # 遇到StopIteration就退出循环
            break

    感谢:https://www.cnblogs.com/wj-1314/p/8490822.html

     
  • 相关阅读:
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车按键启动和蜂鸣器报警
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车指定花式动作
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车指定花式动作
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车指定花式动作
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车前后左右综合实验
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车前后左右综合实验
    ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车前后左右综合实验
    asp中设置session过期时间方法总结
    asp中设置session过期时间方法总结
    ASP.NET关于Session_End触发与否的问题
  • 原文地址:https://www.cnblogs.com/zzy-9318/p/10414367.html
Copyright © 2020-2023  润新知