Python3.5装饰器原理及应用实例详解


Posted in Python onApril 30, 2019

本文实例讲述了Python3.5装饰器原理及应用。分享给大家供大家参考,具体如下:

1、装饰器:

(1)本质:装饰器的本质是函数,其基本语法都是用关键字def去定义的。

(2)功能:装饰其他函数,即:为其他函数添加附加功能

(3)原则:不能修改被装饰的函数的源代码,不能修改被装饰的函数的调用方式。即:装饰器对待被修饰的函数是完全透明的。

(4)简单应用:统计函数运行时间的装饰器

import time
#统计函数运行时间的砖装饰器
def timmer(func):
  def warpper(*args,**kwargs):
    strat_time = time.time()
    func()
    stop_time = time.time()
    print("the func run time is %s" %(stop_time-strat_time))
  return warpper
@timmer
def test1():
  time.sleep(3)
  print("in the test1")
test1()

运行结果:

in the test1
the func run time is 3.000171661376953

(5)实现装饰器知识储备:

a、函数即“变量”

b、高阶函数

c、函数嵌套

d、高阶函数+嵌套函数==》装饰器

2、装饰器知识储备——函数即“变量”

定义一个函数,相当于把函数体赋值给这个函数名。

Python解释器如何回收变量:采用引用计数。当引用有没有了时(门牌号不存在),变量就被回收了。

函数的定义也有内存回收机制,与变量回收机制一样。匿名函数没有函数名,就会被回收。

Python3.5装饰器原理及应用实例详解

变量的使用:先定义再调用,只要在调用之前已经存在(定义)即可;函数即“变量”,函数的使用是一样的。

函数调用顺序:其他的高级语言类似,Python 不允许在函数未声明之前,对其进行引用或者调用

下面的两段代码运行效果一样:

def bar():
  print("in the bar")
def foo():
  print("in the foo")
  bar()
foo()
#python为解释执行,函数foo在调用前已经声明了bar和foo,所以bar和foo无顺序之分
def foo():
  print("in the foo")
  bar()
def bar():
  print("in the bar")
foo()

运行结果:

in the foo
in the bar
in the foo
in the bar

注意:python为解释执行,函数foo在调用前已经声明了bar和foo,所以bar和foo无顺序之分

原理图为:

Python3.5装饰器原理及应用实例详解

3、装饰器知识储备——高阶函数

满足下列其中一种即可称之为高阶函数:

a、把一个函数名当做实参传递给另一个函数(在不修改被装饰函数的情况下为其添加附加功能)

b、返回值中包含函数名(不修改函数的调用方式)

(1)高阶函数示例:

def bar():
  print("in the bar")
def test1(func):
  print(func)  #打印门牌号,即内存地址
  func()
test1(bar)   #门牌号func=bar

运行结果:

<function bar at 0x00BCDFA8>
in the bar

(2)高阶函数的妙处——把一个函数名当做实参传递给另一个函数(在不修改被装饰函数的情况下为其添加附加功能)

import time
def bar():
  time.sleep(3)
  print("in the bar")
#test2在不修改被修饰函数bar的代码时添加了附加的及时功能
def test2(func):
  start_time = time.time()
  func()   #run bar
  stop_time = time.time()
  print("the func run time is %s " %(stop_time-start_time))
#调用方式发生改变,不能像原来的方法去调用被修饰的函数(所以不能实现装饰器的功能)
test2(bar)
#bar()

运行结果:

in the bar
the func run time is 3.000171661376953

(3)高阶函数的妙处——返回值中包含函数名(不修改函数的调用方式)

import time
def bar():
   time.sleep(3)
   print("in the bar")
def test3(func):
  print(func)
  return func
bar = test3(bar)
bar()  #run bar

运行结果:

<function bar at 0x00BADFA8>
in the bar

4、装饰器知识储备——嵌套函数

#函数嵌套
def foo():
  print("in the foo")
  def bar():  #bar函数具有局部变量的特性,不能在外部调用,只能在内部调用
    print("in the bar")
  bar()
foo()

运行结果:

in the foo
in the bar

装饰器应用——模拟网站登录页面,访问需要认证登录页面

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:ZhengzhengLiu
#模拟网站,访问页面和部分需要登录的页面
import timer
user,passwd = "liu","liu123"
def auth(func):
  def wrapper(*args,**kwargs):
    username = input("Username:").strip()
    password = input("Password:").strip()
    if username == user and password == passwd:
      print("\033[32;1mUser has passed authentication!\033[0m")
      res = func(*args,**kwargs)
      print("-----after authentication---")
      return res
    else:
      exit("\033[31;1mInvalid username or password!\033[0m")
  return wrapper
def index():
  print("welcome to index page!")
@auth
def home():
  print("welcome to index home!")
  return "from home"
@auth
def bbs():
  print("welcome to index bbs!")
#函数调用
index()
print(home())
bbs()

运行结果:

welcome to index page!
Username:liu
Password:liu123
User has passed authentication!
welcome to home page!
-----after authentication---
from home
Username:liu
Password:liu123
User has passed authentication!
welcome to bbs page!
-----after authentication---

装饰器带参数

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:ZhengzhengLiu
#模拟网站,访问页面和部分需要登录的页面,多种认证方式
import timer
user,passwd = "liu","liu123"
def auth(auth_type):
  print("auth func:",auth_type)
  def outer_wrapper(func):
    def wrapper(*args, **kwargs):
      print("wrapper func args:",*args, **kwargs)
      if auth_type == "local":
        username = input("Username:").strip()
        password = input("Password:").strip()
        if username == user and password == passwd:
          print("\033[32;1mUser has passed authentication!\033[0m")
          #被装饰的函数中有返回值,装饰器中传入的参数函数要有返回值
          res = func(*args, **kwargs)  #from home
          print("-----after authentication---")
          return res
        else:
          exit("\033[31;1mInvalid username or password!\033[0m")
      elif auth_type == "ldap":
        print("ldap....")
    return wrapper
  return outer_wrapper
def index():
  print("welcome to index page!")
@auth(auth_type="local")    #利用本地登录 home = wrapper()
def home():
  print("welcome to home page!")
  return "from home"
@auth(auth_type="ldap")    #利用远程的ldap登录
def bbs():
  print("welcome to bbs page!")
#函数调用
index()
print(home())   #wrapper()
bbs()

运行结果:

Python3.5装饰器原理及应用实例详解

更多关于Python相关内容可查看本站专题:《Python数据结构与算法教程》、《Python Socket编程技巧总结》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》及《Python入门与进阶经典教程》

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
Python中dictionary items()系列函数的用法实例
Aug 21 Python
Python多线程编程(五):死锁的形成
Apr 05 Python
python迭代器与生成器详解
Mar 10 Python
python学习 流程控制语句详解
Jun 01 Python
Python设计实现的计算器功能完整实例
Aug 18 Python
Python 实现字符串中指定位置插入一个字符
May 02 Python
python去除文件中重复的行实例
Jun 29 Python
Python 2.7中文显示与处理方法
Jul 16 Python
python开启摄像头以及深度学习实现目标检测方法
Aug 03 Python
Python jieba库用法及实例解析
Nov 04 Python
pycharm全局搜索的具体步骤
Jul 28 Python
PyTorch预训练Bert模型的示例
Nov 17 Python
11个Python Pandas小技巧让你的工作更高效(附代码实例)
Apr 30 #Python
python制作图片缩略图
Apr 30 #Python
python获取微信企业号打卡数据并生成windows计划任务
Apr 30 #Python
使用Python实现企业微信的自动打卡功能
Apr 30 #Python
Python/Django后端使用PIL Image生成头像缩略图
Apr 30 #Python
Python3.5迭代器与生成器用法实例分析
Apr 30 #Python
python使用Paramiko模块实现远程文件拷贝
Apr 30 #Python
You might like
PHP 数组遍历顺序理解
2009/09/09 PHP
Yii框架关联查询with用法分析
2014/12/02 PHP
LNMP部署laravel以及xhprof安装使用教程
2017/09/14 PHP
PHP count_chars()函数讲解
2019/02/14 PHP
分析 JavaScript 中令人困惑的变量赋值
2007/08/13 Javascript
Mootools 1.2教程 输入过滤第一部分(数字)
2009/09/15 Javascript
jquery中的$(document).ready()与window.onload的区别
2009/11/18 Javascript
jquery.validate分组验证代码
2011/03/17 Javascript
jQuery lazyLoad图片延迟加载插件的优化改造方法分享
2013/08/13 Javascript
原生js实现改变随意改变div属性style的名称和值的结果
2013/09/26 Javascript
addEventListener()第三个参数useCapture (Boolean)详细解析
2013/11/07 Javascript
js表单提交和submit提交的区别实例分析
2015/12/10 Javascript
jQuery 控制文本框自动缩小字体填充
2017/06/16 jQuery
vue使用原生js实现滚动页面跟踪导航高亮的示例代码
2018/10/25 Javascript
JS实现的冒泡排序,快速排序,插入排序算法示例
2019/03/02 Javascript
Js通过AES加密后PHP用Openssl解密的方法
2019/07/12 Javascript
Vue+Node服务器查询Mongo数据库及页面数据传递操作实例分析
2019/12/20 Javascript
jQuery实现朋友圈查看图片
2020/09/11 jQuery
vue 验证两次输入的密码是否一致的方法示例
2020/09/29 Javascript
[01:34]2016国际邀请赛中国区预选赛IG战队教练采访
2016/06/27 DOTA
简单的编程0基础下Python入门指引
2015/04/01 Python
python中self原理实例分析
2015/04/30 Python
深入解读Python解析XML的几种方式
2016/02/16 Python
简单掌握Python中glob模块查找文件路径的用法
2016/07/05 Python
python学生管理系统
2019/01/30 Python
Python模拟键盘输入自动登录TGP
2020/11/27 Python
HTML5 canvas实现雪花飘落特效
2016/03/08 HTML / CSS
HTML5之多线程(Web Worker)
2019/01/02 HTML / CSS
会计自荐信范文
2014/03/09 职场文书
团购业务员岗位职责
2014/03/15 职场文书
《爱的教育》读书心得
2014/11/08 职场文书
无婚姻登记记录证明
2015/06/18 职场文书
如何书写授权委托书?
2019/06/25 职场文书
PHP命令行与定时任务
2021/04/01 PHP
详解TypeScript中的类型保护
2021/04/29 Javascript
使用 DataAnt 监控 Apache APISIX的原理解析
2022/07/07 Servers