zoukankan      html  css  js  c++  java
  • 装饰器

    函数名,闭包以及装饰器

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

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

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

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

  • 相关阅读:
    Zookeeper 笔记
    个人学习笔记
    VS Window窗体 (C#)程序 连接sql server 数据库
    每周总结 11.9~11.15
    需求分析 第七稿 功能实现进度09
    数据简单清洗和图标联动展示
    IDEA创建文件自动添加作者名及时间
    springcloudalibaba中文文档
    ContractHolder.parseAndValidateMetadata(Ljava/lang/Class;)Ljava/util/List;
    Sentinel fallback失效
  • 原文地址:https://www.cnblogs.com/ALADL/p/9185315.html
Copyright © 2011-2022 走看看