• Python 之 装饰器


    装饰器 中的“器”代指函数

    所以装饰器本质是函数,用来装饰其它函数。例如:为其它函数添加其他功能

    实现装饰器需要的知识:  高阶函数+嵌套函数 == 装饰器

    1、函数就是“变量”

      函数就是“变量”说的就是 函数在内存的存储和回收 和变量类似。

    2、高阶函数(函数调用另一个函数,把函数名作为另一个函数的参数)

     1 def foo():
     2     print("foo ...")
     3     
     4 def fun(fun):
     5     print(fun)
     6     fun()   # fun = foo  相当于foo 和 fun 所指的内存一样
     7 fun(foo)
     8 
     9 #结果  <function foo at 0x0000000003C6E8C8>
    10 #       foo ...

    我们发现 foo.. .执行了 ,是因为foo 和 fun 所指的内存一样 ,函数即变量 可以赋值

    但是我们为什么要多此一举,这样执行呢? 来看下面代码:

     1 import time
     2 def foo():
     3     time.sleep(1)
     4     print("foo ...")
     5 
     6 def fun(fun):
     7     start_time = time.time()
     8     fun()   # fun = foo  相当于foo 和 fun 所指的内存一样
     9     stop_time = time.time()
    10     print("cost time %s" %(stop_time - start_time))
    11 
    12 foo()
    13 fun(foo)
    14 
    15 #结果:foo ...
    16 #     foo ...
    17 #     cost time 1.0000572204589844

    我们发现我们实现了装饰一个函数 我们执行 foo() 和 fun(foo) 效果不一样 ,fun装饰了 foo 函数

    现在 我们已经满足了原则1 :不改变源代码

    我们再看另一个函数:

     1 import time
     2 def bar():
     3     time.sleep(3)
     4     print('in the bar')
     5 def test2(func):
     6     print(func)
     7     return func
     8 print(test2(bar))
     9 print("------------------")
    10 bar=test2(bar)
    11 bar()  #run bar
    12 
    13 #结果
    14 # <function bar at 0x0000000003C6E8C8>
    15 # <function bar at 0x0000000003C6E8C8>
    16 # ------------------
    17 # <function bar at 0x0000000003C6E8C8>
    18 # in the bar

    我们满足了两个原则

    3、嵌套函数

     1 def grandpa():
     2     # x=1
     3     def dad():   #只是定义阶段
     4         x=2
     5         def son():  #只是定义阶段
     6             x=3
     7             print (x)
     8         son()  #必须在这个位置执行
     9     dad()   #必须在这个位置执行  运行dad
    10 grandpa()

    看下面的例子: 假如我们实际场景有100个函数(这里列举两个),这里的函数已经上线运行,现在需要为每一个函数增加一个日志。如果用下面的方式相当于修改了函数的源代码,万一产生错误那么后果很严重(业务崩溃)。

     1 __author__ = "WSX"
     2 
     3 def fun1():
     4     print("fun1")
     5     logger("1")
     6 def fun2():
     7     print("fun2")
     8     logger("2")
     9 
    10 def logger( fun):
    11     print("Logger %s" %fun)
    12 fun1()
    13 fun2()

    所以函数一旦写好不要去修改函数源代码。

    这里我们就需要装饰器。

    装饰器的原则:

    1、不会修改被修饰的函数源码

    2、不要修改函数的调用方式

    现在我们来写一个简单的装饰器:

     1 import time
     2 def timmer(func):  #这是一个装饰器 ,计算时间
     3     def warpper(*args,**kwargs):
     4         start_time=time.time()
     5         func(*args,**kwargs)
     6         stop_time=time.time()
     7         print('the func run time is %s' %(stop_time-start_time))
     8     return warpper
     9 
    10 @timmer   
    11 def test1():
    12     time.sleep(3)
    13     print('in the test1')
    14 test1()
    结果:
    in
    the test1 the func run time is 3.0001718997955322

    上面的代码满足装饰器的原则。现在来分析程序:

    @timmer  相当于test1 = timmer(test1)

    现在我们就完成了一个装饰器。timmer是装饰器 test1是需要被装饰的函数



    下面是老男孩教育Alex写的复杂的带函数返回值的装饰器(堪称高潮):
     1 __author__ = "Alex Li"
     2 import time
     3 user,passwd = 'alex','abc123'
     4 def auth(auth_type):
     5     print("auth func:",auth_type)
     6     def outer_wrapper(func):
     7         def wrapper(*args, **kwargs):
     8             print("wrapper func args:", *args, **kwargs)
     9             if auth_type == "local":
    10                 username = input("Username:").strip()
    11                 password = input("Password:").strip()
    12                 if user == username and passwd == password:
    13                     print("33[32;1mUser has passed authentication33[0m")
    14                     res = func(*args, **kwargs)  # from home
    15                     print("---after authenticaion ")
    16                     return res
    17                 else:
    18                     exit("33[31;1mInvalid username or password33[0m")
    19             elif auth_type == "ldap":
    20                 print("搞毛线ldap,不会。。。。")
    21 
    22         return wrapper
    23     return outer_wrapper
    24 
    25 def index():
    26     print("welcome to index page")
    27 @auth(auth_type="local") # home = wrapper()
    28 def home():
    29     print("welcome to home  page")
    30     return "from home"
    31 
    32 @auth(auth_type="ldap")
    33 def bbs():
    34     print("welcome to bbs  page")
    35 
    36 index()
    37 print(home()) #wrapper()
    38 bbs()
    采用三层嵌套,第二层用于返回需要被装饰的函数的返回值。
     
  • 相关阅读:
    SpringCloud源码解读
    深度剖析Dubbo源码
    十大经典排序算法
    详细介绍Spring 5的那些新特性与增强
    Spring4.x所有Maven依赖
    常见的接口与类 -- Comparable
    java序列化测试
    什么是Java序列化?为什么序列化?序列化有哪些方式?
    java堆、栈、堆栈的区别
    IntelliJ IDEA常用快捷键汇总
  • 原文地址:https://www.cnblogs.com/WSX1994/p/9104305.html
Copyright © 2020-2023  润新知