zoukankan      html  css  js  c++  java
  • lambda 和 iterable

    Lambda 表达式

    你可以使用 Lambda 表达式创建匿名函数,即没有名称的函数。lambda 表达式非常适合快速创建在代码中以后不会用到的函数。尤其对高阶函数或将其他函数作为参数的函数来说,非常实用。

    我们可以使用 lambda 表达式将以下函数

    def multiply(x, y):
        return x * y
    

    简写为:

    double = lambda x, y: x * y

    Lambda 函数的组成部分

    1. 关键字 lambda 表示这是一个 lambda 表达式。
    2. lambda 之后是该匿名函数的一个或多个参数(用英文逗号分隔),然后是一个英文冒号 :。和函数相似,lambda 表达式中的参数名称是随意的。
    3. 最后一部分是被评估并在该函数中返回的表达式,和你可能会在函数中看到的 return 语句很像。

    练习:Lambda 与 Map

    map() 是一个高阶内置函数,接受函数和可迭代对象作为输入,并返回一个将该函数应用到可迭代对象的每个元素的迭代器。下面的代码使用 map() 计算 numbers 中每个列表的均值,并创建列表 averages。测试运行这段代码,看看结果如何。

    通过将 mean 函数替换为在 map() 的调用中定义的 lambda 表达式,重写这段代码,使代码更简练。

    numbers = [
                  [34, 63, 88, 71, 29],
                  [90, 78, 51, 27, 45],
                  [63, 37, 85, 46, 22],
                  [51, 22, 34, 11, 18]
               ]
    
    def mean(num_list):
        return sum(num_list) / len(num_list)
    
    averages = list(map(mean, numbers))
    print(averages)
    

    我这么改:

    mean = lambda num_list: sum(num_list) / len(num_list)
    averages = list(map(mean, numbers))
    

    但其实可以直接将lambda整个写到map参数中averages = list(map(lambda x: sum(x) / len(x), numbers))

    练习:Lambda 与 Filter

    filter() 是一个高阶内置函数,接受函数和可迭代对象作为输入,并返回一个由可迭代对象中的特定元素(该函数针对该元素会返回 True)组成的迭代器。下面的代码使用 filter()cities 中获取长度少于 10 个字符的名称以创建列表 short_cities。测试运行这段代码,看看结果如何。

    通过将 is_short 函数替换为在 filter() 的调用中定义的 lambda 表达式,重写这段代码,使代码更简练。

    cities = ["New York City", "Los Angeles", "Chicago", "Mountain View", "Denver", "Boston"]
    
    def is_short(name):
        return len(name) < 10
    
    short_cities = list(filter(is_short, cities))
    print(short_cities)
    

    改为
    short_cities = list(filter(lambda x: len(x) < 10, cities))

    迭代器和生成器

    迭代器是每次可以返回一个对象元素的对象,例如返回一个列表。我们到目前为止使用的很多内置函数(例如 enumerate)都会返回一个迭代器。

    迭代器是一种表示数据流的对象。这与列表不同,列表是可迭代对象,但不是迭代器,因为它不是数据流。

    生成器是使用函数创建迭代器的简单方式。也可以使用类定义迭代器,更多详情请参阅此处。

    下面是一个叫做 my_range 的生成器函数,它会生成一个从 0 到 (x - 1) 的数字流。

    def my_range(x):
        i = 0
        while i < x:
            yield i
            i += 1
    

    注意,该函数使用了 yield 而不是关键字 return。这样使函数能够一次返回一个值,并且每次被调用时都从停下的位置继续。关键字 yield 是将生成器与普通函数区分开来的依据。

    练习:实现 my_enumerate

    请自己写一个效果和内置函数 enumerate 一样的生成器函数。

    如下所示地调用该函数:

    lessons = ["Why Python Programming", "Data Types and Operators", "Control Flow", "Functions", "Scripting"]
    
    for i, lesson in my_enumerate(lessons, 1):
        print("Lesson {}: {}".format(i, lesson))
    

    应该会输出:

    Lesson 1: Why Python Programming
    Lesson 2: Data Types and Operators
    Lesson 3: Control Flow
    Lesson 4: Functions
    Lesson 5: Scripting
    

    my_enumerate 函数实现:

    def my_enumerate(iterable, start=0):
        """ return enumerate iterable """
        for x in zip(range(start, len(iterable)+start), iterable):
            yield x
    

    练习:Chunker

    如果可迭代对象太大,无法完整地存储在内存中(例如处理大型文件时),每次能够使用一部分很有用。

    实现一个生成器函数 chunker,接受一个可迭代对象并每次生成指定大小的部分数据。

    如下所示地调用该函数:

    for chunk in chunker(range(25), 4):
        print(list(chunk))
    

    应该会输出:

    [0, 1, 2, 3]
    [4, 5, 6, 7]
    [8, 9, 10, 11]
    [12, 13, 14, 15]
    [16, 17, 18, 19]
    [20, 21, 22, 23]
    [24]
    

    chunker 函数实现如下:

    def chunker(iterable, size):
        """Yield successive chunks from iterable of length size."""
        for i in range(0, len(iterable), size):
            yield iterable[i:i + size]
    
    

    可迭代的range()很强大,可以用len()也可以用切片。

    为何要使用生成器?

    你可能会疑问,为何要使用生成器,而不使用列表。下面这段摘自 stack overflow 页面 的内容回答了这个问题:

    生成器是构建迭代器的 “懒惰” 方式。当内存不够存储完整实现的列表时,或者计算每个列表元素的代价很高,你希望尽量推迟计算时,就可以使用生成器。但是这些元素只能遍历一次。

    另一种详细的解释如下(详细说明参见 该 stack overflow 页面。)

    由于使用生成器是一次处理一个数据,在内存和存储的需求上会比使用list方式直接全部生成再存储节省很多资源。

    由此区别,在处理大量数据时,经常使用生成器初步处理数据后,再进行长期存储,而不是使用 list。因为无论使用生成器还是 list,都是使用过就要丢弃的临时数据。既然功能和结果一样,那就不如用生成器。

    但是生成器也有自己的局限,它产生的数据不能回溯,不像list可以任意选择。

  • 相关阅读:
    C# winIO32位,64位的使用(运行时要用管理员身份)
    C#实现的三种方式实现模拟键盘按键
    C#打印日志的小技巧
    write wall ping ifconfig mail last traceroute netstat setup mount
    安装常用工具 zip unzip bzip2 gcc gcc++编译器 cmake编译器
    gzip/gunzip tar -zcf/-zxvf zip /unzip bzip2/bunzip2 tar -cjf/tar -xjf
    help
    Asp.Net 高性能框架 SqlSugar.ORM 2.3
    centos 查看版本(转)
    浅谈OCR之Tesseract
  • 原文地址:https://www.cnblogs.com/warcraft/p/9978164.html
Copyright © 2011-2022 走看看