说明
在Python中,一切函数即对象。函数同时也可视作变量,作为一个返回值。下面通过实际案例来说明下,当函数作为返回值时的使用方式与注意事项
1.初识返回值-函数
- 立即执行函数,获取结果集
def calc_sum(*args):
ax = 0
for n in args:
ax = ax + n
return ax
# 场景1:执行函数,会立即执行,并得到结果集
calc_sum(1, 3, 9)
- 将函数作为返回值,输出并执行
# 另一种场景,不需要立即求和,
def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax+n
return ax
return sum
f = lazy_sum(1, 3, 9)
# 这里输出的是函数对象
print(f)
# 再调用函数 f() ,得到执行结果
f()
2. 辨识函数对象
下面来看看,当给定一组相同的输入参数,得到两个不同的返回函数对象是否相等。
# 每次调用lazy_sum()时,都会返回一个新的函数
f1 = lazy_sum(1, 3, 9)
f2 = lazy_sum(1, 3, 9)
# 且是不同的对象
f1 is f2
# False
可见,虽然输入参数一样,但二者并不是同一个对象。
3. 闭包的注意事项
- 内部函数中引用了外部函数的局部变量
- 返回的函数并没有立刻执行,而是直到调用了f()才执行
内部函数sum()引用外部函数lazy_sum()的局部变量 *args时,可能会导致意料之外的结果 。请看如下示例。
def count():
fs = []
# 外部函数的局部变量i
for i in range(1, 4):
# 注: 这里定义f()函数时,并未传入参数
def f():
# 对外部变量作运算操作、并返回
return i*i
# 添加的是函数对象f,而不是f(),更不是f(i)
fs.append(f)
# 返回列表对象
return fs
# 执行
f1, f2, f3 = count()
print(f1(), f2(), f3())
# 9,9,9
你可能认为调用f1(),f2()和f3()结果应该是1,4,9,但实际是 9,9,9。
正是因为内部函数中引用了外部函数中的变量 i ,但它并非立即执行,等3个函数都返回时,变量i已经变为了3,导致最终结果为 9
谨记
返回函数不要引用任何循环变量,或者后续会发生变化的变量
如何避免?
再创建一个函数,用该函数的参数绑定循环变量当前的值。
无论该循环变量后续如何更改,已绑定到函数参数的值不变
def count():
fs = []
for i in range(1, 4):
def f(i):
def g():
return i*i
return g
# 添加的是 f(i) ,不是f,也不是f()
fs.append(f(i))
return fs
f1, f2, f3 = count()
print(f1(), f2(), f3())