zoukankan      html  css  js  c++  java
  • 一个 lambda 表达式引起的思考

    一个 lambda表达式 引起的思考

    全文都是抄来的

    1. 列表生成式

    1.1 range 函数:

    1.2 列表生成式:

    2. 匿名函数: 原文链接

    Python中的lambda的“一个语法,三个特性,四个用法,一个争论”。

    一个语法

    在Python中,lambda的语法是唯一的。其形式如下:

    其中,lambda是Python预留的关键字,argument_list和expression由用户自定义。具体介绍如下。

    1. 这里的argument_list是参数列表。它的结构与Python中函数(function)的参数列表是一样的。具体来说,argument_list可以有非常多的形式。例如:
    • a, b
    • a=1, b=2
    • *args
    • **kwargs
    • a, b=1, *args
    • ......

    这里的expression是一个关于参数的表达式。表达式中出现的参数需要在argument_list中有定义,并且表达式只能是单行的。以下都是合法的表达式:

    • 1
    • None
    • a + b
    • sum(a)
    • 1 if a >10 else 0
    • ......

    这里的 lambda argument_list: expression 表示的是一个函数。这个函数叫做lambda函数。

     

    三个特性

    lambda函数有如下特性:

    下面是一些lambda函数示例:

     

    四个用法

    由于lambda语法是固定的,其本质上只有一种用法,那就是定义一个lambda函数。在实际中,根据这个lambda函数应用场景的不同,可以将lambda函数的用法扩展为以下几种:

    1. 将lambda函数赋值给一个变量,通过这个变量间接调用该lambda函数。

    1. 将lambda函数赋值给其他函数,从而将其他函数用该lambda函数替换。

    2. 将lambda函数作为其他函数的返回值,返回给调用者。

    1. 将lambda函数作为参数传递给其他函数。
    1. 另外,部分Python库函数也接收函数作为参数,例如 gevent 的 spawn 函数。此时,lambda 函数也能够作为参数传入。

    3. 闭包 原文链接

    1.什么是闭包,闭包必须满足以下3个条件:

    • 必须是一个嵌套的函数。
    • 闭包必须返回嵌套函数。
    • 嵌套函数必须引用一个外部的非全局的局部自由变量。

    举个栗子


    2.闭包优点

    • 避免使用全局变量
    • 可以提供部分数据的隐藏
    • 可以提供更优雅的面向对象实现

    优点1,2 就不说了,很容易理解,关于第三个,例如当在一个类中实现的方法很少时,或者仅有一个方法时,就可以选择使用闭包。

    举个栗子

    闭包的概念差不多就是这样了。

     

    4. 延迟绑定:

     

    5. 解决问题 原文链接

    一、问题描述

    上述式子的输出结果: 预计结果为:0, 2, 4, 6 实际输出为:3, 3, 3, 3

    • 原理:i 在外层作用域 lambda x: x*i 为内层(嵌)函数,他的命名空间中只有 {'x': 1} 没有 i , 所以运行时会向外层函数(这儿是列表解析式函数 [ ])的命名空间中请求 i 而当列表解析式运行时,列表解析式命名空间中的 i 经过循环依次变化为 0-->1-->2-->3 最后固定为 3 , 所以当 lambda x: x*i 内层函数运行时,去外层函数取 i 每次都只能取到 3
    • 解决办法:变闭包作用域为局部作用域。 给内层函数 lambda x: x*i 增加参数,命名空间中有了用来存储每次的 i , 即改成 [lambda x, i=i: x*i for i in range(4)] 这样每一次,内部循环生成一个lambda 函数时, 都会把 --i--作为默认参数传入lambda的命名空间 循环4次实际lambda表达式为: 第一次:lambda x, i=0 第二次:lambda x, i=1 第三次:lambda x, i=2 第四次:lambda x, i=3

    二、上面看不懂就看这儿

    函数fun = [lambda x: x*i for i in range(4)]等价于:如下函数

    查看该函数命名空间及 I 值变化:

    #运行结果为:为了排版美观,我已将输出lambda_函数地址改名为:lam函数1 2 3

    可以看见:就像上面所说的:四次循环中外层函数命名空间中的 i 从 0-->1-->2-->3 最后固定为3, 而在此过程中内嵌函数-Lambda函数中因为没有定义 i 所以只有Lambda 函数动态运行时, 在自己命名空间中找不到 i 才去外层函数复制 i = 3 过来,结果就是所有lambda函数的 i 都为 3, 导致得不到预计输出结果:0,1,2,3 只能得到 3, 3, 3, 3

    • 解决办法:变闭包作用域为局部作用域。

    给内层函数 lambda增加默认参数,命名空间中有了用来存储每次的 i , 即改成 `def lambda(x, i=i) :` 这样每一次, 内部循环生成一个lambda 函数时,都会把 i 作为默认参数传入lambda的命名空间 循环4次实际lambda表达式为: 第一次:lambda( x, i=0) 第二次:lambda(x, i=1) 第三次:lambda(x, i=2) 第四次:lambda(x, i=3)

    这样我们就能得到预计的结果:0, 1, 2, 3

    5. LEGB

    只有函数、类、模块会产生作用域,代码块不会产生作用域。作用域按照变量的定义位置可以划分为4类:

    python解释器查找变量时,会按照顺序依次查找局部作用域--->嵌套作用域--->全局作用域--->内建作用域,在任意一个作用域中找到变量则停止查找,所有作用域查找完成没有找到对应的变量,则抛出 NameError: name 'xxxx' is not defined的异常。

    人生还有意义。那一定是还在找存在的理由

  • 相关阅读:
    C++ template —— 模板基础(一)
    《C++标准程序库》笔记之四
    《C++标准程序库》笔记之三
    《C++标准程序库》笔记之二
    C++标准程序库笔记之一
    JAVA中JPA的主键自增长注解设置
    SVN中服务器地址变更
    JAVA中正则表达式常用的四个方法
    反编译class文件并重新编译的方法
    JAVA中文件与Byte数组相互转换的方法
  • 原文地址:https://www.cnblogs.com/amou/p/9726630.html
Copyright © 2011-2022 走看看