写代码要遵循开发封闭原则,规定已经实现的功能代码不允许被修改,但可以被扩展,通俗来说,不要瞎改改~~
1,关于函数的说明两点
(1):先说一下函数,到底什么是函数:函数即变量,函数存在内存里面,函数名就像门牌号码(内存地址),寻找对应的函数(变量),这里变量test根据内存地址,找到函数test(),变量x根据内存地址找到变量3
(2):所以函数par_b跟par_b()是不同的概念,先看运行结果,可以看到par_b()返回的是函数的运行结果,而par_b返回的内存地址
def par_b(a):
'''返回传入的参数值a '''
return a
print(par_b(2)) # 表示执行函数
print(par_b) #表示是函数,返回的是函数的对象,即函数的内存地址
'''
运行返回值:
2
<function par_b at 0x00000157BB3AC268>
'''
2,装饰器:装饰器本身就是函数,用函数去装饰另外一个函数,即为其他函数附加功能
装饰器不能违背的两个规则:
- 不能改变被修饰函数的源代码
- 不能改变被修饰函数的调用方式
3,装饰器=高阶函数+嵌套函数
3.1:高阶函数:满足下面其一均成为高阶函数
(1)把一个函数名作为实参传给另外一个函数,即把函数当成另外一个函数的参数
(2)返回值中包含函数名,即:一个函数的返回值为另外一个函数(若返回值为该函数本身,则为递归)
第一种情况:
原来一个支付功能函数,现在领导说要统计支付函数花费的时间,这时候不好修改原函数功能的,因为你不知道有多少业务在使用这个函数~~
import time
def order():
'''购买商品'''
time.sleep(1)
print('购买函数')
def order_count(func):
'''购买次数'''
order_start = time.time()
func()
order_stop = time.time()
print('购买花费的时间为:',(order_stop-order_start))
order_count(order)
'''
运行结果:
购买函数
购买花费的时间为: 1.0010454654693604
'''
备注:以上使用了高阶函数的条件一:函数作为参数,但这不是装饰器,显然我们违背了装饰器规则之一:不能改变被修饰函数的调用方式
第二种情况:
import time
def order():
'''购买商品'''
time.sleep(1)
print('购买函数')
def order_count(func):
'''购买次数'''
order_start = time.time()
func()
order_stop = time.time()
print('购买花费的时间为:',(order_stop-order_start))
return func
order=order_count(order)
order() #但其实order函数运行了两次
'''
运行结果:
购买函数
购买花费的时间为: 1.0009815692901611
购买函数
'''
备注:以上添加了高阶函数条件二:返回值中包含函数名,此功能帮我实现了不修改原调用方式的规则
3.2:一看装饰器:所以结合高阶函数的定义,我们来看装饰器:
(1) 把一个函数名当做实参传给另一个函数(不修改被装饰函数的情况下不修改源代码 )
(2) 返回值中包含函数名(不修改函数的调用方式 )
3.3:嵌套函数: 函数套函数,外套里面再穿一个外套,为啥这样穿,冷啊
x = ''
def grandba():
x = '爷爷'
print('第一层返回值:',x)
def dad():
x = '爸爸'
print('第二层返回值:', x)
def son():
x = '儿子'
print('第三层返回值:', x)
son()
dad()
grandba()
'''
执行结果:
第一层返回值: 爷爷
第二层返回值: 爸爸
第三层返回值: 儿子
'''
备注:说一下上面的执行步骤,第一步:读到def grandba():时,首先会把该函数存储到内存中,不会执行该函数内部逻辑,第二步:读到grandba(),才会根据函数名到内存中找到该函数,然后执行,此时才会执行该函数内部的逻辑代码,后面一样的道理
3.4:再看装饰器:在被修饰函数的前面,用@符号调用
4,带参数装饰器
题外话:
之前写的时候函数w2忘记写return w2,然后报错:TypeError: 'NoneType' object is not callable,研究一下原因:
以上运行结果为:
<function order_count.<locals>.w2 at 0x0000029B13E80840>
购买的商品为: apple iphone
购买花费的时间为: 4.394911289215088
运行时打印了w2,输出的内存地址 程序运行到order("apple iphone")内存地址一模一样,流泪啊,恍然大悟了吧,其实到这一步,有一种移花接木的感觉,体会到那句话了,在不该改变原有的调用方式的基础上,给原函数添加附加功能,到这个一步就是:你就我,我就是你啊~~~
另外看到说的很好的:https://www.cnblogs.com/wupeiqi/articles/4980620.html