函数名,闭包以及装饰器
1. 函数名的使用,第一类对象
1.函数名可以像变量一样进行赋值操作 2.函数名可以作为容器(list,dict,tuple)类元素,保存在容器中 3.函数可以返回值返回
函数里面 打印是过程,动作 return是结果 4.函数可以作为参数进行传递
2.闭包
闭包的定义:在内层函数中访问外层函数的局部变量,这个叫闭包
这个时候,外层的局部变量将会常驻内存
1.必须有一个内嵌函数(函数里定义的函数)——这对应函数之间的嵌套 2.内嵌函数必须引用一个定义在闭合范围内(外部函数里)的变量——内部函数引用外部变量 3.外部函数必须返回内嵌函数——必须返回那个内部函数
闭包的目的: 是让内存永远记住一个变量
语法糖: @装饰器名字
总结: def wrapper(fn): def inner(*args,**kwargs): '''目标函数之前你要做什么''' ret = fn(*args,**kwargs) '''目标函数之后你要做什么''' return ret return inner@wrapperdef target():pass
什么叫装饰器: 本质就是函数,为其他函数添加附加功能
装饰器需要把握两个原则:
1.不修改被修饰函数的源代码2.不修改被修饰函数的调用方法我要给函数添加新功能,并且函数原来是什么样,添加完之后还应该是什么样装饰器的知识贮备
装饰器 = 高阶函数+函数嵌套+闭包高阶函数:
1.函数接收的参数是一个函数名2.函数的返回值是一个函数名3.满足上述条件任意一个,都可以称之为高阶函数开放封闭原则:程序一旦上线之后就不应该再继续更改程序源代码
import time def cal(l): start_time = time.time() res = 0 for i in l: time.sleep(0.1) res+=i stop_time = time.time() print("函数的运行时间是%s" %(stop_time-start_time)) return resprint(cal(range(100))) 高阶函数: import timedef foo(): time.sleep(3) print("你好啊,李银河!")def test(func): #print(func) start_time = time_time() func() stop_time = time_time() print("函数运行的时间是%s" $(stop_time-start_time)test(foo)#test是一个高阶函数#函数接收的参数是一个函数名 | |
我们来看装饰器. ⾸先我们先模拟⼀下女娲造⼈.
ok! 很简单. 但是现在问题来了. 上古时期啊. 天⽓很不稳定. 这时候呢⼤旱三年. 女娲再去 造⼈啊就很困难了. 因为啥呢? 没⽔. 也就是说. 女娲想造⼈必须得先和泥. 浇点⼉⽔才能造 ⼈.
搞定. 但是, 我们来想想. 是不是违背了我们最开始的那个约定"开闭原则", 我们是添加了 新的功能. 对添加功能开放. 但是修改了源代码啊. 这个就不好了. 因为开闭原则对修改是封 闭的. 那怎么办. 我们可以这样做.
现在问题⼜来了. 你这个函数写好了. 但是由于你添加了功能. 重新创建了个函数. 在这之 前访问过这个函数的⼈就必须要修改代码来访问新的函数water() 这也要修改代码. 这个也不 好. 依然违背开闭原则. ⽽且. 如果你这个函数被⼤量的⼈访问过. 你让他们所有⼈都去改. 那 你就要倒霉了. 不⼲死你就⻅⿁了. 那怎么办才能既不修改原代码, ⼜能添加新功能呢? 这个时候我们就需要⼀个装饰器了. 装 饰器的作⽤就是在不修改原有代码的基础上, 给函数扩展功能.
1. ⾸先访问warter(create_people).
2. 把你的⽬标函数传递给warter的形参fn. 那么后⾯如果执⾏了fn意味着执⾏了你的⽬ 标函数create_people
3. warter()执⾏就⼀句话. 返回inner函数. 这个时候. 程序认为warter()函数执⾏完. 那么 前⾯的create_people函数名被重新覆盖成inner函数
4. 执⾏create_people函数. 实际上执⾏的是inner函数. ⽽inner中访问的恰恰使我们最开 始传递进去的原始的create_people函数
结论: 我们使⽤warter函数把create_people给包装了⼀下. 在不修改create_people的前提下. 完成了对create_people函数的功能添加
这是⼀个装饰器的雏形. 接下来我们观察⼀下代码. 很不好理解. 所以呢. 我们可以使⽤语法 糖来简化我们的代码
我们发现, 代码运⾏的结果是⼀样的. 所谓的语法糖语法: @装饰器 类似的操作在我们⽣活中还有很多. 比⽅说. 约⼀约.
ok, 接下来. 我们来看⼀下, 我约的话, 我想约个⼈. 比如约wusir, 这时, 我们要给函数添加 ⼀个参数
程序报错. 分析原因: 我们在外⾯访问yue()的时候. 实际上访问的是inner函数. ⽽inner函数 没有参数. 我们给了参数. 这肯定要报错的. 那么该怎么改呢? 给inner加上参数就好了
这样就够了么? 如果我的yue()改成两个参数呢? 你是不是还要改inner. 对了. ⽤*args和 **kwargs来搞定多个参数的问题
搞定. 这时 wen_jin()函数就是⼀个可以处理带参数的函数的装饰器
光有参数还不够. 返回值呢?
返回值和参数我们都搞定了. 接下来给出装饰器的完整模型代码(必须记住)
***这段代码请牢记***