装饰器

函数名,闭包以及装饰器

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

@wrapper
def 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 res

print(cal(range(100)))

高阶函数:
import time
def 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()函数就是⼀个可以处理带参数的函数的装饰器

光有参数还不够. 返回值呢?

返回值和参数我们都搞定了. 接下来给出装饰器的完整模型代码(必须记住)

***这段代码请牢记***

posted @ 2018-06-14 22:39  ALADL  阅读(182)  评论(0编辑  收藏  举报