Python3 学习笔记22_函数式编程-返回函数_20180313

时间:2021-07-18 22:42:25
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# 学习网站:www.liaoxuefeng.com

#****************************************************
# Python3 函数式编程-返回函数 *
#****************************************************
print ("--------------------分割线------------------")

#============
# 函数作为返回值
#============

# 高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回

# 普通的可变参数求和
def calc_sum(*args):
ax = 0
for n in args:
ax = ax + n
return ax

# 不需要立即求和,可以不返回求和的结果,而是返回求和的函数
def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum

func = lazy_sum(1, 3, 5, 6)
print( func ) # <function lazy_sum.<locals>.sum at 0x0000021EDF06E7B8>
print( func() ) # 15

# 调用lazy_sum函数时,每次调用都会返回一个新的函数,即使传入相同的参数
# func1() 和 func2()的调用结果互不影响。
func1 = lazy_sum(2, 3, 4, 5)
func2 = lazy_sum(2, 3, 4, 5)
print( func1==func2 ) # False
print ("--------------------分割线------------------")

#============
# 闭包
#============
'''
在上面lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数
lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都
保存在返回的函数中,这种称为“闭包(Closure)”

注意到返回的函数在其定义内部引用了局部变量args,所以,当一个函数返回
了一个函数后,其内部的局部变量还被新函数所引用
'''

### 一定要注意:返回的函数并没有立刻执行,而是知道调用了fun()才执行
def count():
list_a = []
for i in range(1, 4):
def fun():
return i*i
list_a.append(fun)
return list_a

list_b = list( count() )

for func in list_b:
print( func(),end = ' ' ) # 9 9 9
print()

'''
在上面例子中,每次循环,都创建了一个新的函数,然后,把创建的3个函数都
返回了, 调用func()的结果不是1,4,9。正确结果全部都是9!,原因是返回
的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的
变量i已经变成了3,因此最终的结果是9.

!!!返回闭包时牢记一点:返回函数尽量不要引用任何循环变量,或者后续会发生
!!!变化的变量
'''


# 如果一定要引用循环变量:再创建一个函数,用该函数的参数绑定循环变量
# 当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变
def count1():
def fun(j):
def g():
return j*j
return g
list_a = []
for i in range(1, 4):
list_a.append( fun(i) ) #fun(i)立刻被执行,i的当前值被传入fun()
return list_a

fun1,fun2,fun3 = count1()
print( fun1(), fun2(), fun3() ) # 1 4 9
print ("--------------------分割线------------------")

# 利用闭包返回一个计数器函数,每次调用它返回递增整数
def createCounter():
i = [0]
def counter():
i[0] = i[0] + 1
return i[0]
return counter

aaa = createCounter()
print( aaa(), aaa(), aaa() ) # 1 2 3
'''
解析:
外部变量i=[0],每次调用内部函数,i都指向这个只有一个元素的list
牢记list是可变对象,i指向list这个关系在每次调用中是没有发生改变的
但是list内部第一个元素i[0]指向的数字在每次调用后已经加1了
第一次调用,(内部函数,i=[0]),i[0]+1,i[0]=1,返回1
下一次调用,(内部函数,i=[1]),i[0]+1,i[0]=2,返回2
(注意这里i还是指向原来的那个list,内部函数并没有改变外部变量i的指向)
'''


def createCounter1():
i = 0
def counter():
nonlocal i
i = i + 1
return i
return counter

bbb = createCounter1()
print( bbb(), bbb(), bbb() ) # 1 2 3
'''
解析:nonlocal适用于嵌套函数中内部函数修改外部变量的值,表示这个变量
不是局部变量空间的变量,需要向上一层变量空间找这个变量。
'''