
返回函数
高阶函数不仅可以返回值,还可以返回一个函数
示例:
def sum_func(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum
上例中的sum_func函数内部另定义一个函数sum,sum函数被return返回,并没有被调用执行,所以返回的结果是sum函数的引用地址,可以用变量来接收这个引用对象
# 获得sum_func函数返回的函数对象
_func = sum_func(2,3,4)
# 查看这个对象
_func
<function __main__.sum_func.<locals>.sum()>
从输出上来看,变量_func是一个方法名,而要调用方法则需要在方法名后面添加一对括号
# 调用返回的函数
_func()
9
ok,这里调用了返回的函数,并且输出了2+4+5的值。问题是,参数2, 4, 5是sum_func()的参数,_func()如何获得这些函数呢?这里需要提出闭包的概念
闭包(Closure):内部函数可以引用外部函数的参数和局部变量,当外部函数返了内部回函数时,相关参数和变量都保存在返回的函数中
注意:因为每次调用外部函数的时候,都会重新定义一个内部函数,并将其返回,这样会在计算机内存里开辟不同的内存空间,创建不同的对象,虽然内部函数名字一样,但他们的引用地址其实不一样,所以如果多次调用外部函数返回内部函数,但其实返回的对象都是不一样的
示例:
_func1 = sum_func(1, 3, 5)
_func2 = sum_func(1, 3, 5)
print(_func1 is _func2)
print('_func1 id', id(_func1))
print('_func2 id', id(_func2))
False
_func1 id 4451353872
_func2 id 4451354824
闭包
-
必须有一个内嵌函数(函数里定义的函数)——这对应函数之间的嵌套
-
内嵌函数必须引用一个定义在闭合范围内(外部函数里)的变量——内部函数引用外部变量
-
外部函数必须返回内嵌函数——必须返回那个内部函数
注意:返回的函数并没有立刻执行,而是直到调用了f()才执行
# 定义一个闭包
def count():
fs = []
for i in range(1, 4): # 循环三次,这里的i也算是闭合范围外的变量
def f(): # 闭合范围
return i*i
fs.append(f) # 将f函数保存到fs中
return fs
f1, f2, f3 = count() # 获得三个函数的引用
再来看调用这三个函数的结果
print(f1())
print(f2())
print(f3())
9
9
9
在得到第一个函数的时候,i的值是1;第二个函数返回的i则是2;第三个函数返回的i则是3;按常理来说,这三个函数的返回结果应该是1,4,9才对,而这里全都是9
原因:i其实是闭全范围外的变量,i是一个引用对象,在三次循环后,i的值已经变成了三;此时调用返回的三个函数,它们内部所引用的i都指向了一个内存地址,也就是说是同一个引用对象,那此时的i当然是3,所以最终结果都是9
返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量
那如何解决这种情况呢?请看下面示例:
def count():
def f(j):
def g():
return j*j
return g
fs = []
for i in range(1, 4):
fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
return fs
f1, f2, f3 = count()
print(f1())
print(f2())
print(f3())
1
4
9
原理:再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变
匿名函数
上面的例子写得太过复杂,也不美观,如果一个函数代码块十分简洁,则可以用到匿名函数
匿名函数使用关键字lambda,语法:lambda 参数 : 表达式
,示例:
_func = lambda x : x * x
上例的代码表示创建一个匿名函数(函数没有名字),将此函数的引用赋值给变量_func
冒号左边的x表示形参,如果有多个形参,则用逗号隔开
冒号右边的是执行语句,需要注意的是匿名函数的执行语句只能有一行,如果执行语句有结果,则将结果返回,如果没有结果则返回None,返回结果不需要用到return
下面来调用这个匿名函数:
_func(2)
4
匿名函数的应用:
def count():
f = lambda j : lambda : j*j
fs = []
for i in range(1, 4):
fs.append(f(i))
return fs
f1, f2, f3 = count()
print(f1())
print(f2())
print(f3())
1
4
9
网友评论