再探函数2---函数的嵌套与装饰器
1,函数的嵌套:简单的来说就是函数里面有函数
其实我们前面接触过很多,比如print(len(’人生苦短’))
这里就是print()嵌套了len(),Python会先执行len()函数,得到一个返回值,再由print()打印出来。
再比如print(str())。。。他会先运行里面的函数,然后再实行print函数
来看一下代码:
第九行,我们把calc_sum放到了sum1里面
calc_sum()函数运行结束后会返回变量number,而sum1()函数内部调用了calc_sum(),所以调用sum1()的时候,calc_sum()函数也会执行,并得到返回值。
最后直接调用sum1函数就可以直接得到结果了
最后调用函数时,也只需调用sum1()即可
当然我们还可以写几个函数一直嵌套
需要强调的是return代表返回 每次返回的是该函数的值
2,函数装饰器:装饰函数,给函数增加功能
要求:1,保证使用方法不变
2,同时不改变函数代码
给函数增加功能很简单比如
我们想要再打印出2,这样就可以了
但是这不是装饰器因为改变了函数内部代码
关于使用方法,函数使用方法就是调用方法
2现在要实现这样一个功能.打印结果为‘hello word’
1,保证使用方法不变,就是最后调用函数的时候还是 how(),
2,不改变函数内部代码就是这个函数里面不能直接写代码比如
于是我们很容易想到再用一个函数嵌套
比如在第二行的how后面再加一个word
但是这个时候改变了使用方法,最后会是调用add这个函数,在大量的代码中,你可能还得去后面改调用方法,非常麻烦
那么如何用装饰器来实现:我们知道函数里面是可以有参数的
仔细的看一下这个代码:运行以后会发现
第7行的how是什么东西,我们来打印看一下
结果是
第一个hello是第五行打印出来的
第二个none则是how()
说明how()是个none
3原因,我们是要把这个函数传递到里面,而不是把函数的结果传递到里面去
所以传递函数不能加括号,how()加了括号就变成调用函数
注意第8行,add里面是一个参数,而how()却是一个调用函数
函数名加括号=调用函数,不加括号是一个函数对象
结果指这个how是how函数里面的一个方法对象
而print(how())=none
3,为了不至于出现很多hello,出现混淆我用return写在函数后面
看一下第六行,add(how)之前没有加上return时是none,因为没有返回这个参数值
这个函数里面在运行add函数时,返回了how()就是调用这个how这个函数
此时的结果为:
也就是返回的fun()=‘hello’
而我们要在add函数里面加上一个word就可以
但是这个时候改变了使用方法,所以这并不是正确的装饰器
4,
那么我们又想到用how代替add(how)
但是又出现了一个问题,我们调用函数是 how(),这个时候没有括号了,说明这个how根本不是一个函数,不是函数更不用说调用函数了
这个时候你会发现一个报错
也就是说这个赋值给add(how)的how必须是一个函数才行
5,所以我们返回的必须是一个函数
我们得通过一个函数把现有的函数给包住
函数里面再来写一个函数:
23行的一个函数被add函数包住
第四行是add函数返回的对象
这个过程就是,我们在运行add函数然后返回到wrap ,然后实行wrap下面的功能
第九行how=add(how)这个时候how就是一个函数了
所以最后结果就是
完整的过程就是我们
1,调用add(how)
2,返回wrap
3,运行wrap函数
4,返回how()+word
5,运行how(),打印出hello
6,打印出hello+word
而装饰器的语法是@函数
第六行这个@代表我用来装饰的就是下面这个how函数,而装饰的函数就是add函数
为这个add增加功能
6,不定长参数的装饰器
这是一个计算加法的计算器函数
按照之前的来写的话是这样的
但是会发现报错
结果告诉4个参数有问题
这个函数的参数实际上hi传给了warp
不用@时候是这个样子的
add(calc_sum)实际上是先返回warp函数
然后实现下一步,所以我们warp里面得加上这个参数,并且在func这个参数里面也得加上,所以完整的应该是这样
当然我们用装饰器的语法就是
我们一般在写的时候能会习惯性的写上*args **kwargs,不定长参数和不定长关键字参数
至此这个装饰器就算完成了,我们想要装饰任何函数为之增加一些功能的时候就可以尝试写下来了