一.什么是装饰器

装饰器是用来给函数动态的添加功能的一种技术,属于一种语法糖。通俗一点讲就是:在不会影响原有函数的功能基础上,在原有函数的执行过程中额外的添加上另外一段处理逻辑

二.装饰器功能实现的技术基础--闭包

什么是闭包?闭包就是:一个内部函数被一个外部函数当做返回值进行返回,并且内部函数引用了外部函数提供的变量, 此时将内部函数和引用的外部变量构成的整体称为闭包

闭包的特征?闭包有一个明显的特征就是:引用了外部变量的闭包能够让外部函数不被释放,如果外部函数被释放,就会导致内部函数访问变量时出错

闭包中内部函数如何修改外部函数提供的变量? python3 如果要在闭包内修改外部函数提供的变量,需要使用(nonlocal 变量名称)  进行声明变量不是本地变量,才能进行更改 , python2 中,需要在闭包外先将变量添加到一个列表里,再在闭包内通过下标取出变量,然后进行更改使用。

三.装饰器的使用场景

  引入日志
  函数执行时间统计
  执行函数前预备处理
  执行函数后清理功能
  权限校验等场景
  缓存

三.不带参的装饰器的使用与流程分析

装饰阶段:调用外层函数 (在调用被装饰函数前,已经经历装饰阶段)
运行阶段:调用内层函数和 内层函数的函数体中的func指向的 装饰器下的函数 (运行阶段就是调用被装饰函数的时候)
#coding=utf-8

from django.shortcuts import redirect
from django.http import HttpResponseRedirect
from rest_framework.response import Response def login(func): # 登录验证装饰器,如果未登录就转到登录页面
def login_func(request, *args, **kwargs)
if user_id in request.session
return func(request, *args, **kwargs)
else:
返回还是一个response对象,可以用来设置cookie,session等
redi = HttpResponseRedirect('./user/login')
# 设置cookie,当用户尚未登录时就进行需要登录后才能进行的操作,
# 就先记住用户的当前所处的页面,登录时,通过取回cookie则将用户登录前所处的页面返回
redi.set_cookies('url', request.get_full_path())
return redi
return login_func # 返回时使用了变量名称 api_list 进行接收 @login
def api_list(request):
return Response(status=status.HTTP_200_OK)

api_list(request) # 假设存在这么一个调用逻辑。当然了,在实际的接口,并不是我们开发人员手动去调用的,有用户请求了才会触发。
# request.get_full_path() 获取带参数的当前请求所在的页面的url
# request.path 获取去掉参数的当前请求所在的页面的url 流程说明:
  1.装饰阶段
  首先,会存在这么一个执行流程(这是解释器去进行的):
  api_list = login(api_list),
  将被装饰的函数的引用进行传参,调用装饰器的外层函数,返回内层函数的引用, 返回值使用了被装饰函数的函数名称进行接收,此时的状态就是:
  api_list 指向了 原来 login_func 包含的函数体,func 指向了 原来api_list所指向的函数体,注意是 原来!
  2.运行阶段
    当使用 ret = api_list(request) 进行函数的调用时,因为 api_list 已经指向了 原来 login_func 所包含的函数体,也就是装饰器的内层
    函数。所以,装饰器的内层函数开始执行,func被调用,因为此时 func 指向了原来 api_list 所包含的函数体,最后,被装饰函数得到执行

注意:内层函数也同样要接收 被装饰函数所接收了的参数

四.带参的装饰器的使用与流程分析

# 装饰阶段(装饰阶段时解释器自动进行这段逻辑的):
# 1.beter = outer("lowman"), 结果是创建出新的装饰器 @beter,然后继续进行装饰,就是下面第二步
# 2.zhuangshi = beter(zhuangshi),结果为 zhuangshi 引用指向 原来 inner 的函数体, func 指向了 原来 zhuangshi 的函数体
# 运行阶段:
# 1.调用 zhuangshi(last_name) 时,实际调用的是 inner(last_name, *args, ** kwargs)
# 2.调用 inner 内层函数体中的 func(last_name, * args, **kwargs) 时,实际调用的是 原来 def zhuangshi(last_name) 的函数体
# 带参与不带参的使用区别:
# 带参装饰器与不带参的装饰器的区别仅仅就是带参装饰器可以实现通过装饰器向闭包中传递参数,仅此而已。 def outer(item): def beter(func): first_name = item def inner(last_name, *args, ** kwargs):
ret = func(last_name, * args, **kwargs)
return first_name + ret return inner return beter @outer("lowman")
def zhuangshi(last_name):
return last_name ret = zhuangshi("isbusy") # 调用zhuangshi函数,实际调用的是 内层函数inner, 随后 func 函数被执行, 被装饰函数最终也得以执行
print(ret) # 打印结果: lowmanisbusy

注意:

多个装饰器装饰一个函数:
# 1.装饰阶段:先装饰 内层装饰器,再装饰 外层装饰器;
# 2.运行阶段:先执行 外层装饰器,再执行 内层装饰器;

python 带参与不带参装饰器的使用与流程分析/什么是装饰器/装饰器使用注意事项的更多相关文章

  1. python 全栈开发,Day11(函数名应用,闭包,装饰器初识,带参数以及带返回值的装饰器)

    一.函数名应用 函数名是什么?函数名是函数的名字,本质:变量,特殊的变量. 函数名(),执行此函数. python 规范写法 1. #后面加一个空格,再写内容,就没有波浪线了. 2.一行代码写完,下面 ...

  2. python语法糖之有参装饰器、无参装饰器

    python的装饰器简单来说就是函数的一种形式,是为了扩展原来的函数功能而设计的. 装饰器的特别之处在于它的返回值也是一个函数,可以在不改变原有函数代码的基础上添加新的功能 # 先定义一个函数及引用# ...

  3. Python:高级主题之(属性取值和赋值过程、属性描述符、装饰器)

    Python:高级主题之(属性取值和赋值过程.属性描述符.装饰器) 背景 学习了Javascript才知道原来属性的取值和赋值操作访问的“位置”可能不同.还有词法作用域这个东西,这也是我学习任何一门语 ...

  4. Python面试题集合带答案

    目录 Python基础篇 1:为什么学习Python 2:通过什么途径学习Python 3:谈谈对Python和其他语言的区别 Python的优势: 4:简述解释型和编译型编程语言 5:Python的 ...

  5. 如何写一个Python万能装饰器,既可以装饰有参数的方法,也可以装饰无参数方法,或者有无返回值都可以装饰

    Python中的装饰器,可以有参数,可以有返回值,那么如何能让这个装饰器既可以装饰没有参数没有返回值的方法,又可以装饰有返回值或者有参数的方法呢?有一种万能装饰器,代码如下: def decorate ...

  6. Windows下用Python 3.4+自带的venv模块创建虚拟环境

    Python 3.4+自带了venv模块,用于创建虚拟环境,每个虚拟环境都可以安装一套独立的第三方模块. 本文在Windows 10上操作. 1.创建一个虚拟环境: D:\>mkdir test ...

  7. python实现的、带GUI界面电影票房数据可视化程序

    代码地址如下:http://www.demodashi.com/demo/14588.html 详细说明: Tushare是一个免费.开源的python财经数据接口包.主要实现对股票等金融数据从数据采 ...

  8. Python 实现的、带GUI界面的词云生成器

    代码地址如下:http://www.demodashi.com/demo/14233.html 详细说明: "词云"就是数据可视化的一种形式,给出一段文本,根据文本中词语的出现频率 ...

  9. python元组声明要带逗号

    python元组声明要带逗号 t2, t3, t4 = (2), (2,),() print(type(t2),type(t3), type(t4)) #<class 'int'> < ...

随机推荐

  1. linux下一些常用系统命令

    查看系统打开的文件数 lsof|wc -l 查看当前目录下的文件数 find -type f | wc -l 查看某个目录下的文件数,注意这里/home包括其所有子目录 find /home -typ ...

  2. Object类中通用方法之:toString()方法

    1.Java所有的对象都是Object类的实例,都可以直接调用该类中定义的方法,这些方法称为通用方法 2.toString()方法即为Object类中定义的通用方法之一 3.平时我们如果在控制台直接打 ...

  3. 用java创建UDF,并用于Hive

    典型代码如下: 导入UDF类: import org.apache.hadoop.hive.ql.exec.UDF; public class UpperCassUDF extends UDF{ pu ...

  4. jquery 元素筛选 13.6.20

    <ul> <li>list item 1</li> <li>list item 2</li> <li class="thir ...

  5. 2018.09.29 bzoj3166: [Heoi2013]Alo(01trie+双向链表)

    传送门 01trie经典题目. 我们可以通过计算每个数作为次小值时对答案的贡献. 显然对于每个iii需要求出一个包含a[i]a[i]a[i]且的区间[l,r][l,r][l,r]且区间所有值都小于a[ ...

  6. 2018.09.27 codeforces1045D. Interstellar battle(期望dp)

    传送门 一道有意思的期望dp. 题意是给出一棵树,每个点最开始都有一个gg的概率,有m次修改,每次修改会把某个点gg的概率更换掉,让你求出每次修改之后整个树被分成的连通块的数量的期望(gg掉的点不算) ...

  7. js数组合并(一个数组添加到另一个数组里面)方法

    js定义两个数组. var arrA=[1,2,3]; var arrB=[4,5,6]; 要实现[1,2,3,4,5,6],如果直接arrA.push(arrB); 则arrB只会作为了arrA的一 ...

  8. SQL之经典SQL语句大全

    经典SQL语句大全 一.基础 1.说明:创建数据库CREATE DATABASE database-name 2.说明:删除数据库drop database dbname3.说明:备份sql serv ...

  9. SQL 查找重复记录

    CREATE TABLE product( ID INT IDENTITY(1,1) PRIMARY KEY NOT NULL, Pid INT NOT NULL, Pname VARCHAR(50) ...

  10. iOS的block内存管理

    初始情况下: block本身.__block修饰的变量以及在block内部使用的变量都是在栈里的. __block修饰的变量的地址会作为实参传入block块内部(暂时先这么理解,实际比较复杂).blo ...