Python进阶学习笔记——函数式编程之返回函数&闭包

时间:2022-01-01 02:19:54

 

1、返回函数

Python中除了返回函数值之外,还可以返回函数,就像前面说的,函数也可以看做一个变量,那么返回函数的意义在于什么呢?——延缓函数的调用,有什么应用场景暂且还不知道,后续理解补充。总之,可以想调用该返回的函数的时候再调用。

用慕课网上廖老师的例子说明一下:

def f():

print ('call f()...')

def g():

print('call g()...')

return g

>>> x=f()
call f()...
>>> x()
call g()...

>>> x
<function f.<locals>.g at 0x0000000003E157B8>

eg:延缓调用求积函数

import functools from reduce

def calc_prod(lst):

def lazy_prod(lst):

def prod(x, y):

return x * y

return reduce(prod, lst)

return lazy_prod


2、闭包

闭包也就是内部定义的函数引用了外部定义的变量,且返回内部函数;内部定义的函数无法在外面访问。定义闭包,目的可以防止一些函数被外部代码调用。

摘抄老师的一句话:闭包的特点是返回的函数还引用了外层函数的局部变量,所以,要正确使用闭包,就要确保引用的局部变量在函数返回后不能变。

eg:计算1*1 ,2*2, 3*3的结果

错误的例子是:

def func():
	print('call func()....')
	fs = []
	for i in range(1, 4):
		def mul_i():
			print('call mul_i()...')
			print ('%d * %d = %d'%(i, i, i*i))
			return i*i
		fs.append(mul_i)
	return fs

>>> f1,f2,f3=func()
call func()....
i = 1
i = 2
i = 3
>>> f1()
call mul_i()...
3 * 3 = 9
9
>>> f2()
call mul_i()...
3 * 3 = 9
9
>>> f3()
call mul_i()...
3 * 3 = 9

9

当func返回3个函数的时候,结果没有一个一个立刻执行,而是等3个函数的返回结果都出来的时候才执行,这3个函数所引用的变量都变成了3。类似于返回地址还是返回值的问题

因此,廖老师给出建议——返回函数不要引用任何循环变量,或者后续会发生变化的变量。

那么如果要是用闭包,那么如何改写函数呢?方法就是,定义一个变量,该变量不引用外部的变量。在需要使用时就把它计算出来

def func():
	fs = []
	print('call func()....')
	for i in range(1, 4):
		def mul_i(m = i):
			print('m = %d, i = %d' %(m,i))
			print('call mul_i()....')
			print ('%d * %d = %d'%(m, m, m*m))
			return m*m
		fs.append(mul_i)
	return fs

>>> f1,f2,f3=func()
call func()....
>>> f1()
m = 1, i = 3
call mul_i()....
1 * 1 = 1
1
>>> f2()
m = 2, i = 3
call mul_i()....
2 * 2 = 4
4
>>> f3()
m = 3, i = 3
call mul_i()....
3 * 3 = 9
9


-----------

看到另一个方法,这里补充:

def func():
	fs = []
	print('call func()....')
	for i in range(1, 4):
		def mul_i():
			print('call mul_i()....')
			print ('%d * %d = %d'%(i, i, i*i))
			return i*i
		fs.append(mul_i())
	return fs

>>> f1,f2,f3=func()
call func()....
call mul_i()....
1 * 1 = 1
call mul_i()....
2 * 2 = 4
call mul_i()....
3 * 3 = 9

方法二理解为立刻返回结果,而方法一理解为延缓返回结果。方法二已经不是一个闭包了。

方法二中返回的函数立刻执行了

---------------------

廖老师给出的方法是再定义一个函数

def func():
	print('call func()...')
	fs = []
	for i in range(1, 4):
		def f(x):
			print('call f()...')
			print('x = %d' %x)
			def g():
				print('call g()...')
				print('x = %d' %x)
				return x*x
			return g
		r = f(i)
		fs.append(r)
	return fs
>>> f1,f2,f3=func()
call func()...
call f()...
x = 1
call f()...
x = 2
call f()...
x = 3
>>> f1()
call g()...
x = 1
1
>>> f2()
call g()...
x = 2
4
>>> f3()
call g()...
x = 3
9