装饰器:(语法糖)

本质是函数,它是赋予函数新功能,但是不改变函数的源代码及调用方式
 
原则:
1.不能修改被装饰函数的源代码
2.不能修改被装饰函数的调用方式
3.函数的返回值也不变
这两点简而言之,就是装饰器对被装饰函数来说是透明的
 
知识储备
1.函数即变量
     比如定义了一个变量  x = ‘gkx’   python是一门解释性语言,解释了‘gkx’,并给它分配了内存地址,而 x 就是这个内存地址的一个索引,类似门牌号。
同理可得 def test():print('gkx') 定义了一个函数  test是它的门牌号,print('gkx')分配了一个内存地址。故可以理解为函数即变量。
2.高阶函数
    a.把一个函数名当作实参传递给另外一个函数(在不改变函数源代码的情况
为其添加新功能)
    b.返回值中包含函数名(不改变函数调用方式
3.嵌套函数
 嵌套函数  在一个函数的函数体内,用def声明一个新函数
def foo():
print('in the foo.')
def bar():
print('in the bar.')
bar() #要调用bar需要在在函数体内调用,类似局部变量
foo()

装饰器例子:仅针对注释的几段,对其进行排序,如下红字

 import time       #python的debug都是先读取最外层框架(最外层没有缩进),最外层中如果涉及到调用,再接着运行调用内容。  第一步

 def timer(func): #当读取到 @timer的时候,相当于运行 test1 = timer(test1),所以会返回来读取 warpper  第三步
def warpper(*args,**kwargs):
start_time = time.time()
func(*args,**kwargs)  #此时才是真正意义上运行 test1函数 第六步
       return func(*args,**kwargs) #保证fun()返回值也不变
stop_time = time.time()
print('in the test1() %s'%(stop_time-start_time))
return warpper #把test1当作实参传递给 timer,timer(test1),此时返回的是 函数warpper的内存地址 第四步 #然后此时运行到 python里的语法【@timer】
@timer #相当于 test1 = timer(test1),返回warpper的内存地址,此时如果运行 test1(),相当于 warpper(),warpper就开始执行其函数体内的语句 第二步
def test1():
time.sleep(1)
print('in the test1')
    return ‘from test1’
test1() #此时运行的 test1()已经不是直接运行 test1函数了,是经过@timer,转换成运行 warpper()了 第五步

 装饰器进阶版,装饰器本身带参数

 user = 'gkx'
pass_1 = ''
def decorator(auth_type):
print("auth type",auth_type)
def outer_warpper(func):
def warpper(*args,**kwargs):
if auth_type == 'local':
username = input("id")
password = input("password")
if username == user and password == pass_1:
print('\033[32;1mwelcome\033[0m')
res = func(*args,**kwargs)
print("after decorator")
return res
else:
print('\033[31;1mwrong info\033[0m')
elif auth_type == 'ldap':
print('我不会')
return warpper
return outer_warpper #当访问到这里的返回值时候,会继续执行 warpper,然后执行逻辑就和上面提到的timer一样了 @decorator(auth_type='local')  #这里分成两部分看,第一部分是 调用decorator(auth_type = 'local'),此时返回outer_wrapper的内存地址
                    #在第一部分的基础上,此时加上@,变成了 @outer_wrapper,相当于 homepage = outer_wrapper(wrapper),再返回了wrapper的内存地址 def homepage():
26   print('home page')
   return 'from home'

 @decorator(auth_type='ldap')
def bbs():
print('in bbs') print(homepage())
bbs()

装饰器三个重要补充:

#一共有三个

# 第一个
from functools import wraps def outer(func):
@wraps(func) #wraps模块
def inner(*args,**kwargs):
print('装饰前')
ret = func(*args,**kwargs)
print('装饰后')
return ret
return inner @outer
def holiday(day):
''' :param day: days of vacation
:return:
'''
print("放假%s"%day)
return '好开心' print(holiday.__name__) #import wraps后此时打印holiday函数名,否则是 inner函数名
print(holiday.__doc__)
ret = holiday(3)
print(ret) # 第二个,当装饰器带参数
import time
FLAG = False
def out_timmer(flag):
def timmer(func):
def inner(*args,**kwargs):
if flag:
start = time.time()
ret = func()
end = time.time()
print(start-end)
return ret
else:
ret = func()
return ret
return inner
return timmer
@out_timmer(FLAG) #可以看成两部 1, timmer = out_timmer(FLAG) 2, @timmer
def shop1():
time.sleep(0.01)
print('buy first thing') @out_timmer(FLAG)
def shop2():
time.sleep(0.01)
print('buy second thing') shop1()
shop2() #第三个 函数被多个装饰器调用
def wrapper1(func): #func-----> f
def inner1():
print('wrapper1,befor func')
ret = func()
print('wrapper1,after func') #这一句运行完,但是inner2还没结束,要返回inner2继续运行【print('wrapper2,after func')】
return ret
return inner1 def wrapper2(func): #func-----> inner1 inner1传给了wrapper2
def inner2():
print('wrapper2,befor func') #运行完这一句,下一句运行inner1,故返回到wrapper1继续运行
ret = func() #inner1
print('wrapper2,after func')
return ret
return inner2 @wrapper2 #wrapper1 执行完后,执行wrapper2 但是此时传入的不是f,是 inner1,相当于 wrapper(inner1) == inner2 然后继续运行warpper2
@wrapper1 #先执行到这里,因为语法糖要找离它最近的函数。wrapper2没找到,故往下运行。此时函数 f传给wrapper1 相当于 f = wrapper1(f) 即为 inner1
def f():
print('in the f')
f() #--------->>调用inner2

Python—装饰器详解的更多相关文章

  1. Python装饰器详解

    python中的装饰器是一个用得非常多的东西,我们可以把一些特定的方法.通用的方法写成一个个装饰器,这就为调用这些方法提供一个非常大的便利,如此提高我们代码的可读性以及简洁性,以及可扩展性. 在学习p ...

  2. python设计模式之装饰器详解(三)

    python的装饰器使用是python语言一个非常重要的部分,装饰器是程序设计模式中装饰模式的具体化,python提供了特殊的语法糖可以非常方便的实现装饰模式. 系列文章 python设计模式之单例模 ...

  3. Python中的各种装饰器详解

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

  4. Python全栈开发之8、装饰器详解

    一文让你彻底明白Python装饰器原理,从此面试工作再也不怕了.转载请注明出处http://www.cnblogs.com/Wxtrkbc/p/5486253.html 一.装饰器 装饰器可以使函数执 ...

  5. python函数装饰器详解

    python装饰器(fuctional decorators)简单来说就是修改其他函数的函数. 这样的函数需要满足两个个条件: 1.不能修改原函数的源代码 2.不能改变原函数的调用方式 需要达到的效果 ...

  6. python之装饰器详解

    这几天翻看python语法,看到装饰器这里着实卡了一阵,最初认为也就是个函数指针的用法,但仔细研究后发现,不止这么简单. 首先很多资料将装饰器定义为AOP的范畴,也就是Aspect Oriented ...

  7. python装饰器1:函数装饰器详解

    装饰器1:函数装饰器 装饰器2:类装饰器 装饰器3:进阶 先混个眼熟 谁可以作为装饰器(可以将谁编写成装饰器): 函数 方法 实现了__call__的可调用类 装饰器可以去装饰谁(谁可以被装饰): 函 ...

  8. python 叠加装饰器详解

    def out1(func1): #7.func1=in2的内存地址,就是in2 print('out1') def in1(): #8.调用函数index() 因为函数在in1里,所以首先运行in1 ...

  9. (转)面向对象(深入)|python描述器详解

    原文:https://zhuanlan.zhihu.com/p/32764345 https://www.cnblogs.com/aademeng/articles/7262645.html----- ...

随机推荐

  1. selenium 淘宝登入反爬虫解决方案(亲测有效)

    前言 目前在对淘宝进行数据爬取的时候都会碰到,登入时的滑块问题,无论是手动还是脚本都不成功.这里的很重要一个原因是很多的网站都对selenium做了反爬虫机制.接下来是笔者参考网上的网友们的方法亲自测 ...

  2. C语言进阶之路(一)----C语言的内存四区模型

    内存四区模型:操作系统给C/C++编写的程序分配内存,通常将分配的内存划分为以下四个区域:1.栈区:存放局部变量,用完由操作系统自动释放2.堆区:动态分配给程序的内存区域,由程序员手动释放3.数据区: ...

  3. window中的attrib命令

    attrib -s -h -r autorun.infattrib +s +h +r autorun.infattrib -s -h -r my.icoattrib +s +h +r my.ico

  4. CFRunLoop 源码学习笔记(CF-1151.16)

    1.CFRunLoopModeRef 什么时候创建的? 在调用__CFRunLoopFindMode(rl, modeName, create) 1.1)首先通过modeName 在RunLoop 中 ...

  5. linux iptables详解(转)

    概述 netfilter/iptables(简称为iptables)组成Linux平台下的包过滤防火墙,与大多数的Linux软件一样,这个包过滤防火墙是免费的,它可以代替昂贵的商业防火墙解决方案,完成 ...

  6. 双系统安装Ubuntu

    U盘制作教程参考Ubuntu官网 1.Ubuntu安装 1)分出空闲空间:首先,在现有计算机下划出一个专门给Ubuntu的磁盘分区,推荐Windows自带的磁盘管理工具.快捷键“win+X”-> ...

  7. C/C++ strict-aliasing

    最近发现了一个奇怪的编译参数-fno-strict-aliasing,好奇之下做了一点研究: 重点参考Understanding C/C++ Strict Aliasing: 所谓的aliasing就 ...

  8. Zeu.js

    一个生成各种 GIF 动画的 JavaScript 类库,非常适合用于让你的数据展示变得更加地生动.使用起来也非常简单,有数据展示需求的同学可以尝试一下.https://shzlw.github.io ...

  9. GoldenGate BR(bounded Recovery)简单说明

    背景 Oracle数据库的在线日志包含已提交的和未提交的事务,但OGG只会将已提交的事务写入到队列文件.因此,针对未提交的事务,特别是未提交的长事务,OGG会怎样处理呢? 有些长事务是在批处理作业中, ...

  10. DataTable插件报错:Uncaught TypeError: Cannot read property 'style' of undefined

    DataTable插件报错:Uncaught TypeError: Cannot read property 'style' of undefined 原因:table 中定义的列和aoColumns ...