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连接mysql调用存储过程示例
Mar 05 Python
python异步任务队列示例
Apr 01 Python
Python程序设计入门(4)模块和包
Jun 16 Python
Python类的动态修改的实例方法
Mar 24 Python
Django开发的简易留言板案例详解
Dec 04 Python
python多任务及返回值的处理方法
Jan 22 Python
Python 互换字典的键值对实例
Feb 12 Python
python钉钉机器人运维脚本监控实例
Feb 20 Python
Python使用Pickle模块进行数据保存和读取的讲解
Apr 09 Python
详解python statistics模块及函数用法
Oct 27 Python
解决python gdal投影坐标系转换的问题
Jan 17 Python
详解Python3 定义一个跨越多行的字符串的多种方法
Sep 06 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 IE中下载附件问题解决方法
2014/01/07 PHP
php分页代码学习示例分享
2014/02/20 PHP
Laravel 5 框架入门(三)
2015/04/09 PHP
php实现的一段简单概率相关代码
2016/05/30 PHP
详解Yii2.0使用AR联表查询实例
2017/06/16 PHP
php实现数字补零的方法总结
2018/09/12 PHP
jquery easyui滚动条部分设置介绍
2013/09/12 Javascript
IE与FF下javascript获取网页及窗口大小的区别详解
2014/01/14 Javascript
js简单判断移动端系统的方法
2016/02/25 Javascript
jQuery获取同级元素的简单代码
2016/07/09 Javascript
ui组件之input多选下拉实现方法(带有搜索功能)
2016/07/14 Javascript
Angular2下使用pdf插件的方法详解
2017/04/29 Javascript
React-Native做一个文本输入框组件的实现代码
2017/08/10 Javascript
PHP自动加载autoload和命名空间的应用小结
2017/12/01 Javascript
vue2.0 computed 计算list循环后累加值的实例
2018/03/07 Javascript
基于vue中keep-alive缓存问题的解决方法
2018/09/21 Javascript
用element的upload组件实现多图片上传和压缩的示例代码
2019/02/12 Javascript
解决Angularjs异步操作后台请求用$q.all排列先后顺序问题
2019/11/29 Javascript
Vue组件跨层级获取组件操作
2020/07/27 Javascript
Vue基于localStorage存储信息代码实例
2020/11/16 Javascript
js实现简易计算器小功能
2020/11/18 Javascript
python Pygame的具体使用讲解
2017/11/03 Python
Python中数组,列表:冒号的灵活用法介绍(np数组,列表倒序)
2018/04/18 Python
python主线程捕获子线程的方法
2018/06/17 Python
Spring http服务远程调用实现过程解析
2020/06/11 Python
keras 自定义loss层+接受输入实例
2020/06/28 Python
浅析HTML5 meta viewport参数
2020/10/28 HTML / CSS
极度干燥澳大利亚官方网站:Superdry澳大利亚
2019/03/28 全球购物
幼儿园运动会入场词
2014/02/10 职场文书
春节请假条
2014/04/11 职场文书
安全生产目标责任书
2014/04/14 职场文书
大学生就业自我推荐信
2014/05/10 职场文书
幼儿园保育员责任书
2014/07/22 职场文书
环境卫生倡议书
2014/08/29 职场文书
个人收入证明模板
2014/09/18 职场文书
个人借款协议书范本
2014/11/17 职场文书