从0.1开始学Python——[16]

从0.1开始学Python——[16]


上次说到高阶函数是接收函数作为参数或将函数作为返回值的函数,并且学习了接收函数作为参数的高阶函数,所以本次学习聚焦于第二种,也就是将函数作为返回值的高阶函数。

另一种高阶函数

先举一个这种高阶函数的简单例子。

def gaojie():
    q = '环首刀'
    def didi():
        print(q)
    return didi
w = gaojie()
w()
环首刀

这个变量q的值根据前面命名空间的东西可以知道,只有didi()函数能访问,外部无法访问,所以就形成了一个闭包,就是这种高阶函数的别称。创建闭包的目的在于创建一些只有当前函数能访问的变量,用于藏匿私有数据。比如一些需要设置变量初始值的,而后续使用函数初始变量会不断改变而且不希望被外部干扰的函数。

def qiupingjunshu():
    suoqiu = []
    def suanpingjunshu(i):
        suoqiu.append(i)
        return sum(suoqiu)/len(suoqiu)
    return suanpingjunshu
r = qiupingjunshu()
print(r(10))
print(r(20))
suoqiu = [10]
print(r(30))
10.0
15.0
20.0

可以看出外部干扰suoqiu = [10]这种语句无法对继续调用r这个闭包产生任何影响。
综上所述,创建闭包需要满足一些要素:嵌套格式的函数;将内部函数作为返回值返回;内部函数必须使用到外部函数的变量

装饰器

说白了就是装饰函数用的,因为调用代码不一定输出,函数工作以后可能什么也不会显示,装饰器就可以提示用户函数已经运行了。这种提示可以直接写在函数里面,但是函数很多那一个个写就很繁琐,而且函数发生改动还得一个个修改提示信息。
另外还违反开闭原则(OCP),即设计出的程序只能扩展但是不能修改的原则。所谓扩展,就是在别的函数里面调用这个函数,所以不是修改函数。例如,我创建一个加法函数,那么别人就不能在这个函数里面加入其他语句,但是别人可以定义一个新函数,把我的函数放进去,这样在调用我的函数以外的语句中写其他内容就可以了,这就叫扩展:

def jiafa(a,b):  # 这里面不能写别的了
    r = a + b
    return r


def xinjiafa(a,b):  # 但是这里面可以 
    print('start') 
    r = jiafa(a,b)
    print('end')
    return r

r = xinjiafa(111,222)
print(r)
start
end
333

注意,在函数里面调用其他函数需要注意你返回的是什么,比如调用xinjiafa(a,b)函数,你想要的实际上是jiafa(a,b)函数的返回值,所以要记得return jiafa(a,b)这一步。另外注意,这种函数扩展的过程不同于上面讲到的高阶函数,因为那种是函数嵌套在内定义的,而这种是定义在外面,所以新函数的形参也需要和里面要调用的参数保持一致,但是不需要和原定义的参数形参字母一样,比如xinjiafa(a,b)可以修改为xinjiafa(c,d),只要把里面调用命令r = jiafa(a,b)也改成r = jiafa(c,d)保持形参一致就行了。
上面说完OCP原则的问题,下面就是解决普遍装饰的问题,因为一个个改不现实,太费力。可以用函数解决这个问题,用创造装饰器的函数装饰所有函数,也就是用这个函数扩展所有函数。

def jiafa(a,b):  # 这里面不能写别的了
    r = a + b
    return r


def fn():
	print('suck')


def zhuangshiqi(k):
    '''
    作用是扩展其他函数,显示函数的开始和结束
    参数:
        k代表要扩展的函数对象,注意是函数对象,没括号
    :return:
    '''
    def zhuangshi(*args,**kwargs):  # 对于这个函数,内部没有再嵌套其他定义函数了,所以内外需要参数一致,但是外部zhuangshiqi()的参数就不需要和这个的一致,因为这个函数嵌套在人家里面
        print('执行已开始')  # *args,**kwargs分别接收所有位置参数和关键字参数,有没有都行,所以可以传输所有函数
        r = k(*args,**kwargs)
        print('执行已结束')
        return r
    return zhuangshi

f = zhuangshiqi(fn)
f1 = zhuangshiqi(jiafa)
r = f()  # 注意调用装饰器函数的时候需要看输入的函数是否有参数,有的话你也要输入实参。
r1 = f1(111,222)
print(r1)
执行已开始
suck
执行已结束
执行已开始
执行已结束
333

或者在定义函数之前加一个@装饰器函数对象就行了。

@zhuangshiqi
def fn():
    print('suck')
    
fn()
执行已开始
suck
执行已结束

可以@好几个装饰器,这样会被多个装饰器装饰,顺序是从内向外,或者由近及远,就是靠近下面函数的装饰器的装饰效果也离函数调用结果最近。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值