学以致用三十六-----弄懂python装饰器
看了海峰老师讲解的装饰器视频,讲解的非常棒。根据视频,记录笔记如下:
装饰器:
1、本质是函数,用def来定义。功能就是用来(装饰)其他函数,为其他函数添加附加功能
现有两个函数如下,
def test1():
pass def test2()
pass test1()
test2()
需要添加一个记录日志的功能
原始方法,在每个函数里添加
def test1():
pass
print('logging') def test2()
pass
print('logging') test1()
test2()
再进一步,增加一个函数,test1和test2来调用
1 def logger():
2 print('logging')
3
4 def test1():
5 pass
6 logger()
7
8 def test2()
9 pass
10 logger()
11
12 test1()
13 test2()
那假如有上百上千个函数,并且是正常在线的代码,也这样处理吗?很显然这是不可能的
因此装饰器的原则
2、a. 不能修改被装饰的函数的源代码
b.不能修改被装饰的函数的调用方式
实现装饰器知识储备:
3、a. 函数即“变量”
b. 高阶函数
c.嵌套函数
高阶函数+嵌套函数==装饰器
============================================
再来看一下以下几个场景
场景一
def bar():
print("in the bar") def foo():
print ("in the foo")
bar() foo()
场景二
def foo():
print ("in the foo")
bar() def bar():
print("in the bar") foo()
场景一和场景二的不同之处在于,一个bar()在foo()之前,一个在foo()之后,但两者结果一样,按理说python应该是从上往下一行一行执行,为啥场景二也没有问题呢
经过断点debug调试,发现在debug的过程中,程序会先把函数都过一遍,顺序是 def foo() ----> def bar() ----> foo() ----> print ("in the foo") ---> bar() -----> print (in the bar)
那再看场景三
def foo():
print ("in the foo")
bar() foo() def bar():
print("in the bar")
按照之前的解释,程序也会先把函数都过一遍,然后去执行。但场景三确报错了,会提示 name 'bar' is not defined,debug显示 def foo() 后直接到 foo(), 就直接执行foo()函数了,并没有往下走。
因为遇到foo(),就表示要去执行foo函数,而此时 bar并未在内存建立‘’门牌号‘’,因此会报错
看下面这张图,函数相当于变量的集合。

高阶函数:
a:把一个函数名当做实参传给另外一个函数
(在不修改被装饰函数源代码的情况下为其添加功能)
b:返回值中包含函数名(不修改函数的调用方式),一定要有return,返回该函数的内存地址
如下面的代码
import time
def bar():
time.sleep(3)
print('in the bar') def test1(func):
start_time = time.time()
func()
stop_time = time.time()
print("the func run time is %s" %(stop_time-start_time)) test1(bar)
此时相当于 func=bar, func() 会执行bar函数
执行结果
in the bar
the func run time is 3.0004918575286865
返回值包含函数名,如
import time
def bar():
time.sleep(3)
print('in the bar') def test2(func):
print(func)
return func test2(bar)
print("================")
print(test2(bar))
结果
<function bar at 0x000001B343BF3EA0>
================
<function bar at 0x000001B343BF3EA0>
<function bar at 0x000001B343BF3EA0>
print(test2(bar))先打印 func,然后返回func的内存地址。于是又打印一遍
换一种方式
import time
def bar():
time.sleep(3)
print('in the bar') def test2(func):
print(func)
return func t=test2(bar)
print("================")
# print(test2(bar))
t()
此时会去执行bar函数
结果
<function bar at 0x00000246AECB3EA0>
================
in the bar
那把 t 换成 bar 呢
import time
def bar():
time.sleep(3)
print('in the bar') def test2(func):
print(func)
return func bar=test2(bar)
print("================")
# print(test2(bar))
bar()
结果和上面是一样的。可以看出函数的调用方式没有改变,结果是一样的
因此引出了装饰器
import time
def test2(func):
# print(func)
print("auth---")
return func @test2
def bar():
time.sleep(1)
print('in the bar')
bar()
执行结果:
auth---
in the bar
在 in the bar 前面加了一段auth---,没有改变bar()的代码
这样装饰器就解释明白了
当然还有多层嵌套和装饰,带参数的装饰器,以后需要加强练习再补充。
学以致用三十六-----弄懂python装饰器的更多相关文章
- 利用世界杯,读懂 Python 装饰器
Python 装饰器是在面试过程高频被问到的问题,装饰器也是一个非常好用的特性, 熟练掌握装饰器会让你的编程思路更加宽广,程序也更加 pythonic. 今天就结合最近的世界杯带大家理解下装饰器. 德 ...
- 一篇文章搞懂Python装饰器所有用法
01. 装饰器语法糖 如果你接触 Python 有一段时间了的话,想必你对 @ 符号一定不陌生了,没错 @ 符号就是装饰器的语法糖. 它放在一个函数开始定义的地方,它就像一顶帽子一样戴在这个函数的头上 ...
- Unity3D学习笔记(三十六):Shader着色器(3)- 光照
光照模型:用数学的方法模拟现实世界中的光照效果. 场景中模型身上的光反射到相机中的光线: 1.漫反射:产生明暗效果 2.高光反射:产生镜面反射,物体中有最亮且比较耀眼的一部分 3.自发光: 4.环 ...
- 一篇关于Python装饰器的博文
这是一篇关于python装饰器的博文 在学习python的过程中处处受阻,之前的学习中Python的装饰器学习了好几遍也没能真正的弄懂.这一次抓住视频猛啃了一波,就连python大佬讲解装饰器起来也需 ...
- 第三百六十六节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的bool组合查询
第三百六十六节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的bool组合查询 bool查询说明 filter:[],字段的过滤,不参与打分must:[] ...
- 第三百五十六节,Python分布式爬虫打造搜索引擎Scrapy精讲—scrapy分布式爬虫要点
第三百五十六节,Python分布式爬虫打造搜索引擎Scrapy精讲—scrapy分布式爬虫要点 1.分布式爬虫原理 2.分布式爬虫优点 3.分布式爬虫需要解决的问题
- 第三百四十六节,Python分布式爬虫打造搜索引擎Scrapy精讲—Requests请求和Response响应介绍
第三百四十六节,Python分布式爬虫打造搜索引擎Scrapy精讲—Requests请求和Response响应介绍 Requests请求 Requests请求就是我们在爬虫文件写的Requests() ...
- 第三百三十六节,web爬虫讲解2—urllib库中使用xpath表达式—BeautifulSoup基础
第三百三十六节,web爬虫讲解2—urllib库中使用xpath表达式—BeautifulSoup基础 在urllib中,我们一样可以使用xpath表达式进行信息提取,此时,你需要首先安装lxml模块 ...
- 剑指Offer(三十六):两个链表的第一个公共结点
剑指Offer(三十六):两个链表的第一个公共结点 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.ne ...
随机推荐
- linux下用数据泵导入导出(impdp、expdp)
expdp和impdp expdp假设a用户的默认表空间是a,导出用户a所有数据: 如果是多实例 需要在命令行或终端手工指定实例 set ORACLE_SID=实例名 否则回报ORA-12560: T ...
- SpringCloud-day03-服务注册与发现组件Eureka
5.服务注册与发现组件Eureka 5.1Eureka简介: Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中 ...
- 深入理解C++11【5】
[深入理解C++11[5]] 1.原子操作与C++11原子类型 C++98 中的原子操作.mutex.pthread: #include<pthread.h> #include <i ...
- 微信小程序-数据绑定
在js页面的data字典内添加绑定数据 data: { "messg":"helloworld " }, 在wxml页面内使用{{}}调用数据
- 通过代码启动appium服务
如果选择npm安装的最新版appium 1.8.0以上版本,启动appium的时候,你会发现无法使用Node.js命令 这里给出两种方法来启动appim: 方法一: /** * 使用AppiumSer ...
- appium 版本更新后的方法变化更新收集 ---持续更新
在高版本的android手机(例如android 7.0 , 8.0等等),必须使用高版本的appium, 以及对应的selenium版本,那么很多的appium或者selenium方法会变得无法直接 ...
- 关于Image创建的内存管理
image创建方法 [UIImage imageNamed:imageName] 上述方法创建的image,会常驻在内存中,不会随着imageView的dealloc而释放内存. NSString * ...
- python 基础 ----- 变量
------ python注释 注释的作用:代码提示,运行时忽略不必要的代码 注释的三种方式: 1.“#” 单行注释 2.多行注释 三个单引号 和三个双引号都可以 注释的快捷键 Ctrl + ...
- 48-设置tomcat虚拟路径的两种方法(Eclipse、tomcat、IDEA)
设置tomcat虚拟路径的两种方法(Eclipse.tomcat.IDEA) 三种方式设置虚拟服务器路径如果我们要实现一个上传文件的功能,但是又想要上传的文件不会随着自己web服务器的重启而不能访问了 ...
- JavaSE基础知识(5)—面向对象(方法的重写与重载)
一.重写 1.说明 子类对继承过来的父类的方法进行改造,这种现象称为方法的重写或覆盖或覆写(Override) 2.要求 方法签名完全一致,jdk5.0之后,允许返回类型可以是子类类型,权限修饰符可以 ...