zoukankan      html  css  js  c++  java
  • 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方法,一下字就可以搞定。

  • 相关阅读:
    【转】win8.1下安装ubuntu
    Codeforces 1025G Company Acquisitions (概率期望)
    Codeforces 997D Cycles in Product (点分治、DP计数)
    Codeforces 997E Good Subsegments (线段树)
    Codeforces 1188E Problem from Red Panda (计数)
    Codeforces 1284E New Year and Castle Building (计算几何)
    Codeforces 1322D Reality Show (DP)
    AtCoder AGC043C Giant Graph (图论、SG函数、FWT)
    Codeforces 1305F Kuroni and the Punishment (随机化)
    AtCoder AGC022E Median Replace (字符串、自动机、贪心、计数)
  • 原文地址:https://www.cnblogs.com/Andy963/p/7043718.html
Copyright © 2011-2022 走看看