• lambda 函数所引起的闭包问题


    之前在某本书上看到一道题,要求是:用字符串sign中的每一个字符去分割s字符串,并得到最后的结果

    s = 'ab;cd|efg|hi,jkl|mnopq;rst,uvw/xyz'
    sign = ';|/,'
    

     书中给的答案是这样的:

    def my_split(s, sign):
    	s = [s]
    	for i in sign:
    		t = []
    		for x in s:
    			map(lambda x: t.extend(x.split(i)), s)
    		s = t
    	return s
    print(my_split(s,sign))
    

     按这逻辑推导了一遍,觉得这map, lambda用得高明,但是我一运行,结果竟然是[],什么鬼,说好的分割呢,全割没了?

    难道编辑器有问题?难道我写错代码了,都不是,又重新推导了一遍,问题依旧!

    然后我就按这种逻辑,自定义了一个函数,只不过没用map, lambda来实现:

    def my_split(s, sign):
    	for i in sign:
    		t = []
    		if type(s) is list:
    			for j in s:
    				t.extend(j.split(i))
    		else:
    			s = s.split(i)
    			t.extend(s)
    		s = t
    	return s
    print(my_split(s,sign))
    

     代码是啰嗦了点,但是能正常运行,得到我想要的结果:

    ['ab', 'cd', 'efg', 'hi', 'jkl', 'mn', 'opq', 'rst', 'uvw', 'xyz']
    

     既然这样,那说明逻辑上没有问题啊,那为什么结果不对呢?

    经过多方请教无果:

    不得不重新一步一步推导,然后看到函数my_split内部的lambda函数,这种样式不禁想到了闭包。就做了下面这样一个尝试:

    def my_split(s, sign):
    	s = [s]
    	for i in sign:
    		t = []
    		for x in s:
    			#map(lambda x: t.extend(x.split(i)), s)
    			def lambd(i, t, x, s):
    				map(t.extend(x.split(i)),s)
    			lambd(i, t, x, s) # 注意这行,这里执行了lambd函数
    		s = t
    	return s
    print(my_split(s,sign))
    

     这里将lambda函数那行注释掉,重新定义了一个lambd函数,做了两样的事,但是,因为加上了执行,最终我得到了想要的结果。

    事实上,lambda函数也可以赋值给一个对象,如:splits=lambda x: t.extend(x.split(i)),最后通过调用这个splits函数,达到执行的目的

    但这样就失去了lambda 匿名函数的作用,并且由于外面需要执行map方法,所以这里是无法完成的。

    最后,要说的就是,如上面定义的lamdb函数一样,它引用了外部变量如i, t ,x,s,形成了闭包,但是,如果最后不调用lamdb(i,t,x,s),

    每次只是产生 了一个函数对象,并没有执行。

    这里可以做这样一个测试:

    def my_split(s, sign):
    	s = [s]
    	for i in sign:
    		t = []
    		#map(lambda x: t.extend(x.split(i)), s)
    		for x in s:
    			def lambd(i, t, x, s):
    				map(t.extend(x.split(i)),s)
    			#lambd(i, t, x, s) # 注释掉
    		s = t
    		print(s) # 打印出来
    	return s
    print(my_split(s,sign))
    

     我们将函数执行语句注释掉,然后每次内循环完成的时候打印s,结果发现每次s都是空列表。原因是lambd函数没有执行,

    所以t列表一直为空,每次内循环执行完成后,将t赋值给了s,导致s也一直为空,这就是为什么最后得到的结果为空的原因。

    这种lambda函数形成闭包比较隐蔽,如果没仔细看,很容易忽略,所以一定要注意。

    当然这里更简单的办法是用正则表达式的re.split方法,一下字就可以搞定。

  • 相关阅读:
    day10函数名称空间与作用域(3)
    day10函数参数使用(2)
    day10函数基础(1)
    文件处理
    vue打包时semver.js版本报错
    js修改日期
    vue click事件获取当前元素属性
    js截取关键字之后的字符串
    css 清除浮动
    纯CSS绘制三角形
  • 原文地址:https://www.cnblogs.com/Andy963/p/7043718.html
Copyright © 2020-2023  润新知