一个 lambda 表达式引发的思考

一个 lambda表达式 引发的思考

 
 
 
 
 

全文都是抄来的html

1. 列表生成式

1.1 range 函数:

 
 
 
 
 

1.2 列表生成式:

 
 
 
 
 

2. 匿名函数: 原文连接

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

一个语法

在Python中,lambda的语法是惟一的。其形式以下:web

 
 
 
 
 

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

  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函数。api

 

三个特性

lambda函数有以下特性:闭包

 
 
 
 
 

下面是一些lambda函数示例:app

 
 
 
 
 

 

四个用法

因为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. 解决问题 原文连接

1、问题描述

 
 
 
 
 

上述式子的输出结果: 预计结果为: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
 
 
 
 
 

2、上面看不懂就看这儿

函数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的异常。

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

相关文章
相关标签/搜索