一.什么是装饰器

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

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

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

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

闭包中内部函数如何修改外部函数提供的变量? 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. OpenSource.iOS.ProtobufWithObjective-C

    2. 在iOS(Mac OS X)中使用protobuf 2.0 构建protoc A) 下载最新的protobuf版本 B) 依据README中的步骤依次进行 2.1 添加protobuf到工程中 ...

  2. dedecms模型类的引入

  3. APP自动化测试怎么测?

    一般来说工具还有技术都是千篇一律 测试测到最后还是业务能力...

  4. 彻底测试全部拷贝list相关操作的区别python

    1.用浅拷贝后修改数字,可以起到与原数据分离的效果 import copy origin = [, , [, ]] #origin 里边有三个元素:, ,[, ] cop1=origin.copy() ...

  5. cocos2d-js IOS接facebook插件

    当前测试版本:cocos2d-x 3.8.1       3.7也试用,之下的版本没测过,一般是路径改变,文件名称一般不会变 注:当前工程是通过控制台new的工程,不是cocosStudio创建的工程 ...

  6. Cannot initialize Cluster. Please check your configuration for mapreduce.framework.name and the correspond server addresses.

    解决方法: <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-m ...

  7. MVC--SSM和SSH简介

  8. 转@RequestParam,@PathParam,@PathVariable等注解区别

    转自:http://blog.csdn.net/u011410529/article/details/66974974 @RequestParam 和 @PathVariable 注解是用于从requ ...

  9. Android在layout xml中使用include[转]

    在Android的layout样式定义中,可以使用xml文件方便的实现,有时候为了模块的复用,使用include标签可以达到此目的.例如: <include layout="@layo ...

  10. stdafx.h、stdafx.cpp是干什么用的?为什么我的每一个cpp文件都必须包含stdafx.h? Windows和MFC的include文件都非常大,即使有一个快速的处理程序,编

    sstdafx.h.stdafx.cpp是干什么用的?为什么我的每一个cpp文件都必须包含stdafx.h? Windows和MFC的include文件都非常大,即使有一个快速的处理程序,编译程序也要 ...