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

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

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

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("")
  6. def fun2():
  7. print("fun2")
  8. logger("")
  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()
  1. 结果:
    in the test1
  2. the func run time is 3.0001718997955322

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

  1. @timmer 相当于test1 = timmer(test1)
  2. 现在我们就完成了一个装饰器。timmer是装饰器 test1是需要被装饰的函数
  3.  
  4. 下面是老男孩教育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("\033[32;1mUser has passed authentication\033[0m")
  14. res = func(*args, **kwargs) # from home
  15. print("---after authenticaion ")
  16. return res
  17. else:
  18. exit("\033[31;1mInvalid username or password\033[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()
  1. 采用三层嵌套,第二层用于返回需要被装饰的函数的返回值。
  1.  

Python 之 装饰器的更多相关文章

  1. Python各式装饰器

    Python装饰器,分两部分,一是装饰器本身的定义,一是被装饰器对象的定义. 一.函数式装饰器:装饰器本身是一个函数. 1.装饰函数:被装饰对象是一个函数 [1]装饰器无参数: a.被装饰对象无参数: ...

  2. Python札记 -- 装饰器补充

    本随笔是对Python札记 -- 装饰器的一些补充. 使用装饰器的时候,被装饰函数的一些属性会丢失,比如如下代码: #!/usr/bin/env python def deco(func): def ...

  3. python基础——装饰器

    python基础——装饰器 由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数. >>> def now(): ... print('2015-3-25 ...

  4. 【转】详解Python的装饰器

    原文链接:http://python.jobbole.com/86717/ Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现 ...

  5. 两个实用的Python的装饰器

    两个实用的Python的装饰器 超时函数 这个函数的作用在于可以给任意可能会hang住的函数添加超时功能,这个功能在编写外部API调用 .网络爬虫.数据库查询的时候特别有用 timeout装饰器的代码 ...

  6. python 基础——装饰器

    python 的装饰器,其实用到了以下几个语言特点: 1. 一切皆对象 2. 函数可以嵌套定义 3. 闭包,可以延长变量作用域 4. *args 和 **kwargs 可变参数 第1点,一切皆对象,包 ...

  7. 理解Python中的装饰器//这篇文章将python的装饰器来龙去脉说的很清楚,故转过来存档

    转自:http://www.cnblogs.com/rollenholt/archive/2012/05/02/2479833.html 这篇文章将python的装饰器来龙去脉说的很清楚,故转过来存档 ...

  8. python基础—装饰器

    python基础-装饰器 定义:一个函数,可以接受一个函数作为参数,对该函数进行一些包装,不改变函数的本身. def foo(): return 123 a=foo(); b=foo; print(a ...

  9. 详解Python的装饰器

    Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现了say_hello()和say_goodbye()两个函数. def sa ...

  10. 关于python的装饰器(初解)

    在python中,装饰器(decorator)是一个主要的函数,在工作中,有了装饰器简直如虎添翼,许多公司面试题也会考装饰器,而装饰器的意思又很难让人理解. python中,装饰器是一个帮函数动态增加 ...

随机推荐

  1. 转:MongoDB · 引擎特性 · journal 与 oplog,究竟谁先写入?

    转:MongoDB · 引擎特性 · journal 与 oplog,究竟谁先写入? 数据库内核月报 链接:http://mysql.taobao.org/monthly/2018/05/07/ Mo ...

  2. 四 Mixer

    Mixer在应用程序和基础架构后端之间提供通过中介层.它的设计将策略决策移出应用层,用运维人员能够控制的配置取而代之. Mixer的设计目的是改变层次之间的边界,以此降低总体复杂性.从服务代码中剔除策 ...

  3. IC卡和RFID卡的区别(网上说的都不准确)

    其实IC卡是卡类型的称呼,IC卡和RFID卡不应该在一起对比的,和IC卡在一起对比的应该是ID卡. RFID卡是其实是对卡技术类型称呼. IC为卡类型称呼(Integrated Circuit Car ...

  4. “百度杯”CTF比赛 2017 二月场(Misc Web)

    爆破-1: 打开链接,是502 我直接在后面加个变量传参数:?a=1 出了一段代码 var_dump()函数中,用了$$a,可能用了超全局变量GLOBALS 给hello参数传个GLOBALS 得到f ...

  5. LaTeX数学公式基础

    LaTeX数学公式 参考:https://www.cnblogs.com/Sinte-Beuve/p/6160905.html 原博客显示有点问题,重新搬运整理LaTeX数学公式部分的基本用法 基础 ...

  6. Ajax笔记(一)

    Ajax三步骤: Asynchronous Javascript And XML 1.运用HTML和CSS实现页面,表达信息: 2.运用XMLHttpRequest和web服务器进行数据的异步交换: ...

  7. 关于web.xml中的<welcome-file-list>中的默认首页文件

    先看我的配置文件: <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome ...

  8. 关于c#分支语句和分支嵌套还有变量的作用域。

    分支语句: if....else if....else 必须以 if  开头 后面加括号写入需要判断的内容. 举个栗子说明一下 if (bool类型(比较表达式))  //  他会判断括号内的条件是否 ...

  9. Unity3d 脚本与C#Socket服务器传输数据

    Test.cs脚本 ------------------------------------------------------------------------------------------ ...

  10. bzoj2134 错选单位

    传送门 题目 Input n很大,为了避免读入耗时太多, 输入文件只有5个整数参数n, A, B, C, a1, 由上交的程序产生数列a. 下面给出pascal/C/C++的读入语句和产生序列的语句( ...