
简单来说,编程中提到的 lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数。这一用法跟所谓 λ 演算(题目说明里的维基链接)的关系,有点像原子d和质能方程的关系,差别其实还是挺大的。
不谈形式化的 λ 演算,只说有实际用途的匿名函数。先举一个普通的 Python 例子:将一个 list 里的每个元素都平方:
map( lambda x: xx, [y for y in range(10)] )
这个写法要好过
def sq(x):
return x x
map(sq, [y for y in range(10)])
,因为后者多定义了一个(污染环境的)函数,尤其如果这个函数只会使用一次的话。而且第一种写法实际上更易读,因
为那个映射到列表上的函数具体是要做什么,非常一目了然。如果你仔细观察自己的代码,会发现这种场景其实很常见:你在某处就真的只需要一个能做一件事情的
函数而已,连它叫什么名字都无关紧要。Lambda 表达式就可以用来做这件事。
进一步讲,匿名函数本质上就是一个函数,它所抽象出来的东西是一组运算。这是什么意思呢?类比
a = [1, 2, 3]
和
f = lambda x : x + 1
,你会发现,等号右边的东西完全可以脱离等号左边的东西而存在,等号左边的名字只是右边之实体的标识符。如果你能习惯 [1, 2, 3] 单独存在,那么 lambda x : x + 1 也能单独存在其实也就不难理解了,它的意义就是给「某个数加一」这一运算本身。
现在回头来看 map() 函数,它可以将一个函数映射到一个可枚举类型上面。沿用上面给出的 a 和 f,可以写:
map(f, a)
也就是将函数 f 依次套用在 a 的每一个元素上面,获得结果 [2, 3, 4]。现在用 lambda 表达式来替换 f,就变成:
map( lambda x : x + 1, [1, 2, 3] )
会不会觉得现在很一目了然了?尤其是类比
a = [1, 2, 3]
r = []
for each in a:
rappend(each+1)
这样的写法时,你会发现自己如果能将「遍历列表,给遇到的每个元素都做某种运算」的过程从一个循环里抽象出来成为一个函数 map,然后用 lambda 表达式将这种运算作
为参数传给 map 的话,考虑事情的思维层级会高出一些来,需要顾及的细节也少了一点。Python 之中,类似能用到 lambda
表达式的「高级」函数还有 reduce、filter 等等,很多语言也都有这样的工具(不过这些特性最好不要在 Python 中用太多,原因详见 的评论部分)。这种能够接受一个函数作为参数的函数叫做「高阶函数」(higher-order function),是来自函数式编程(functional programming)的思想。
和
其他很多语言相比,Python 的 lambda 限制多多,最严重的当属它只能由一条表达式组成。这个限制主要是为了防止滥用,因为当人们发觉
lambda 很方便,就比较容易滥用,可是用多了会让程序看起来不那么清晰,毕竟每个人对于抽象层级的忍耐 / 理解程度都有所不同。
没有块作用域:即作用域不是以{}包围的,其作用域完成由函数来决定,因而if /for等语句中的花括号不是独立的作用域。
如前述,JS的在函数中定义的局部变量只对这个函数内部可见,称之谓函数作用域。
嵌套作用域变量搜索规则:当在函数中引用一个变量时,JS会搜索当前函数作用域,如果没有找到则搜索其上层作用域,一直到全局作用域。
[javascript] view plain copy print
var value = 'global';
var f1 = function(){
consolelog(v1); //global
};
f1();
var f2 = function(){
var v1 ='local';
consolelog(v1); //local
};
解释:这是相当优雅的代码(如果首次看见可能会一头雾水:),包围函数(function(){})的第一对括号向脚本返回未命名的函数,随后一对空括号立即执行返回的未命名函数,括号内为匿名函数的参数。
来个带参数的例子:
(function(arg){
alert(arg+100);
})(20);
这个例子返回120。
重要用途:可以用它创建命名空间,只要把所有的代码都写在这个特殊的函数包装内,那么外部就不能访问,除非被允许。
(function(){
function $(id){
return documentgetElementById(id);
}
function __addClass(id,className,classValue){
$(id)styleclassName=classValue;
}
window['mySpace']={};
window['mySpace']['addClass']=__addClass;
})();
for(var i=0;i<=3;i++){ setTimeout(function() { consolelog(i) }, 10);}
答案:打印4次4
这道题涉及了异步、作用域、闭包
settimeout是异步执行,10ms后往任务队列里面添加一个任务,只有主线上的全部执行完,才会执行任务队列里的任务,当主线执行完成后,i是4,所以此时再去执行任务队列里的任务时,i全部是4了。对于打印4次是:
每一次for循环的时候,settimeout都执行一次,但是里面的函数没有被执行,而是被放到了任务队列里面,等待执行,for循环了4次,就放了4次,当主线程执行完成后,才进入任务队列里面执行。
(注意:for循环从开始到结束的过程,需要维持几微秒或几毫秒。)
当我把var 变成let 时
for(let i=0;i<=3;i++){ setTimeout(function() { consolelog(i) }, 10);}
打印出的是:0,1,2,3
当解决变量作用域,
因为for循环头部的let不仅将i绑定到for循环快中,事实上它将其重新绑定到循环体的每一次迭代中,确保上一次迭代结束的值重新被赋值。setTimeout里面的function()属于一个新的域,通过 var 定义的变量是无法传入到这个函数执行域中的,通过使用 let 来声明块变量,这时候变量就能作用于这个块,所以 function就能使用 i 这个变量了;这个匿名函数的参数作用域 和 for参数的作用域 不一样,是利用了这一点来完成的。这个匿名函数的作用域有点类似类的属性,是可以被内层方法使用的。
查了一下百度的一个答案:
setTimeout是一次执行函数,这里是10ms后执行,仅仅执行一次;for(var i=0;i<=3;i++),i的每次取值都是执行setTimeout这个函数,并没有执行setTimeout里面的function(即闭包函数),setTimeout里面的function是有setTimeout的定时触动的,也就是10ms后执行,也就是说i从0~3时,一共执行了4次的setTimeout()函数,此时的i的值是4,由于for语句的执行速度远小于1秒,所以,1秒后,由setTimeout()函数定时触动的闭包函数function()开始执行,alert(i);i的值已经是4了,所以相继打印4次i
https://wwwcnblogscom/wangwenhui/p/7657654html
@在Matlab中一般表示取地址的意思(不知道你C语言有没学过,如果学过,那就能理解地址就是指针的概念)。
第一个表示取qbyg函数的地址;
第二个表示取匿名函数的地址,匿名函数用后面的括号表名。匿名函数只能用一次,下次用进需要重新定义。
可以使用闭包的方法:functionaa(){vara='hello';returnfunction(){returna;}}然后在外面接收:varfn=aa();//返回一个匿名函数vara=fn();//获取到匿名函数中的返回值根据作用域链的原理内部的函数可以访问到外部函数的变量,然后将获取的变量返回即可。
楼主你好!
要解决这道题目并不难,只需要理解匿名lambda是如何使用的便可;
“lambda 表达式1:表达式2”其实就是定义了一个函数,传入表达式1的参数,按表达式2的形式返回,因此,该语句也就返回了一个函数对象,请看如下代码:
def demo(x):return xx
lambda_demo = lambda x:xx
以上代码中demo函数和lambda_demo是等效的,都是可以调用的对象,传入一个参数,返回这个参数的平方。
那这题就不难解了,其实做的事情就是定义了两层:
1)第一层函数是传入一个参数,返回第二层定义的函数对象
2)第二层是不传入参数,返回第一层参数的平方
套用lambda的定义,便不难解出正确答案:
# -- coding: utf-8 --def count():
'''这是原函数'''
def f(j):
def g():
return jj
return g
fs = []
for i in range(1, 4):
fsappend(f(i))
return fs
def edited_count():
'''这是修改后的函数'''
fs= []
for i in range(1, 4):
fsappend((lambda x:(lambda :xx))(i))
return fs
def evol_count():
'''更加pythonic的写法'''
return [(lambda x:(lambda :xx))(i) for i in range(1,4)]
'''一行式写法'''
one_line_count = lambda :[(lambda x:(lambda :xx))(i) for i in range(1,4)]
再分析一下楼主两段错误代码:
第一段的报错原因在于,楼主混淆了变量的有效空间,lambda中的变量只是形式,并不会对外部变量进行录入,所以在f函数中传入的j,并不会记录在lambda中,因此,在最后执行的时候,列表中的三个函数是第一段代码段中的demo函数,需要楼主传入一个参数,再返回你传入参数的平方。
第二段代码看代码逻辑应该是正确的,这个修改发生了什么呢?其实你定义的lambda函数形式变成了这样:
def demo(x=1):return xx
也就是变相的把变量的值给定义了,出错的原因应该是你在调用的时候很可能是以这样的形式调用:count()() 才导致了报错。
希望楼主能够深入理解lambda以及python的命名空间,今后遇到这样的题目便能迎刃而解了。
望采纳,谢谢!~
大家都知道,我们在用Vue的时候经常要用到this,例如要在方法中访问data中的变量,例如要在调用定义在methods中的方法等等。但有时候你发现像往常一样简单的用thisxxx会报出this的undefined。这是因为在某些情况下,this并不是和普通情况下指当前组件。下面我来总结一下我用this时遇到的一些问题
在匿名函数中想使用this来调用data或methods中的变量,方法时,会报出thi为undefined。
那么怎么解决呢?
可以看到这里还是能获取这个匿名函数外层的变量的count=0,那么我们只要用一个变量把this引用起来就好
那如果我们不想定义一个引用变量,那该如何解决——我们可以用箭头函数
其实箭头函数这里的this是指外层函数的this,因为箭头函数是没有定义this,当在箭头函数内部用到this后会从他的父级作用域寻找。他父级就是query()函数,在这函数里使用this是指向当前组件的,所以这个直接在这函数里定义的箭头函数也是如此。
有些场景下我们会结合匿名函数和箭头函数,用this的时候就要非常小心了。
就像这次我在实现一个 轮询查询订单状态 的功能时就用了这样的结构:
轮询第一次的时候直接执行,一共轮询五次,随后的四次轮询采用setTimeOut三秒一次,可以看到这里实际上使用axios请求的方法是被定义在一个变量为f的匿名函数里,而axios的回调函数使用箭头函数写的。因此里就不能用this了,因为如果在这里用了this,实际上是匿名函数的this,也就是undefined了。所以一般把this是定义为匿名函数外层,然后在里面引用。
Javascript的this真的是复杂,不像Java那样明显,平时还是得多注意一下,这玩意真的就是空指针问题一样困扰Js开发者。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)