python中的闭包和装饰器
重新学习完了函数,是时候将其中的一些重点重新捋一捋了,本次总结的东西只有闭包和装饰器
1.闭包
闭包是python函数中的一个比较重要功能,一般闭包都是用在装饰器上,一般学完闭包就会去学习装饰器,这俩个总是让初学时的我一脸懵逼,现在好好捋一捋。
1.1 闭包的定义
- 内层函数对外层函数(非全局)调用
- 闭包一般存在于内部函数
- 闭包都是一般一层一层退出,最后退出函数外返回值
- (自我理解)函数外部对于函数内部的调用以及对内部函数的值调用
1.2 闭包的判断
__closure__的使用
- ####不是闭包
- name = 'test'
- def func():
- def inner():
- print(name)
- return inner()
- f = func()
- print(f.__closure__[0].cell_contents)
- #结果
- TypeError: 'NoneType' object is not subscriptable
- #结果就是没有闭包调用的值,就不是闭包
- #是闭包
- def func():
- name = 'test'
- age = 18
- def inner():
- print(name)
- print(age)
- return inner
- f = func()
- print(f.__closure__[0].cell_contents)
- print(f.__closure__[1].cell_contents)
- #结果
- 18
- test
1.3 闭包的机制
在编译器中碰到函数,在函数执行结束后会将名称空间关闭,不过对于闭包,内部机制是碰到闭包的空间就不会关闭,在一段时候不在调用或者使用后才会关闭
1.4 闭包的使用以及使用场景
用闭包的形式写一个数字的连加
- def func(i):
- num = 1
- def inner():
- nonlocal num
- num += i
- print(num)
- return inner
- f = func(3)
- for i in range(5):
- f()
上面这个只是一个很简单的功能,对于闭包在一些日常的使用场景有
装饰器和爬虫的一部分使用
2.装饰器(一个需求引发的血案)
需求:公司内一个项目运营了一段时间,TeamLeader觉得现在的代码执行效率有点低下,需要对现有函数的的执行效率进行一次测试。
2.1 直接调用
在最开始的时候没想完整,只是实现功能,代码如下
- import time
- def func1():
- print('func1')
- time.sleep(0.5)
- def func2():
- print('func2')
- time.sleep(0.6)
- def test(f):
- stat_time = time.time()
- f()
- end_time = time.time()
- print('执行效率为%s'%(end_time-stat_time))
- test(func1)
- test(func2)
- #结果
- func1
- 执行效率为0.5010201930999756
- func2
- 执行效率为0.6002087593078613
对于这个,你的领导绝对想要杀了你,这样的话打乱了整个项目的函数调用顺序,测试一遍,全部的函数基本没法用了,需要改进,改进目的是减少对于已有函数的影响
2.2 一定的伪装
- import time
- def func1():
- print('func1')
- time.sleep(0.5)
- def func2():
- print('func2')
- time.sleep(0.6)
- def test(f):
- stat_time = time.time()
- f()
- end_time = time.time()
- print('执行效率为%s'%(end_time-stat_time))
- f = func1
- func1 =test
- func1(f)
- f1 = func2
- func2=test
- func2(f1)
- #结果和上面一致
和最开始的那个版本相比呢,有一定的伪装了,可是执行的方式和以前就不一样了,还有一个比较重要的是这样执行函数不能传参数,项目的函数之间调用一定是有参数的,所以这个版本也PASS了,继续想吧,下个阶段实现的目的是执行函数和以前一致
2.3 比较好的伪装
- def test(f):
- def inner():
- stat_time = time.time()
- f()
- end_time = time.time()
- print('执行效率为%s'%(end_time-stat_time))
- return inner
- #结果
- func1
- 执行效率为0.5008118152618408
不太好理解,借用老师上课的一张图,有空了在去做动图吧
这个版本已经和非常接近完整版了,不过python中有语法糖的功能,可以将上述函数尽量减少
2.4 伪装成功-装饰器
看一下代码
- import time
- def test(f):
- def inner():
- stat_time = time.time()
- f()
- end_time = time.time()
- print('执行效率为%s'%(end_time-stat_time))
- return inner
- @test
- def func1():
- print('func1')
- time.sleep(0.5)
- @test
- def func2():
- print('func2')
- time.sleep(0.6)
- func1()
- func2()
看一下这个@test就是这个小老鼠,装饰器加上下面的函数名,就自动生成一个装饰器,这样就看着很顺眼了,不过还有一些功能啊,有些函数还是有一些参数需要传参,貌似现在的功能还没有实现哎,在改改吧。
2.5 装饰器的传参
既然传参,那么参数的数量就不一致,这样就需要动态传参了,看代码
- import time
- def test(f):
- def inner(*args,**kwargs):
- stat_time = time.time()
- f(*args,**kwargs)
- end_time = time.time()
- print('执行效率为%s'%(end_time-stat_time))
- return inner
- @test
- def func1(x):
- print(x)
- time.sleep(0.5)
- @test
- def func2(x,y):
- print(x,y)
- time.sleep(0.6)
- func1('a')
- func2('b',[1,2,3,4])
- #结果
- a
- 执行效率为0.5004942417144775
- b [1, 2, 3, 4]
- 执行效率为0.6011292934417725
2.6 装饰器的返回值
上面那个应该是已经非常非常接近于完全体了,即使是函数,有了传参,那么就有返回值,那么返回值怎么才能看到呢,代码如下
- import time
- def test(f):
- def inner(*args,**kwargs):
- stat_time = time.time()
- r1 =f(*args,**kwargs)
- end_time = time.time()
- print('执行效率为%s'%(end_time-stat_time))
- return r1
- return inner
- @test
- def func1(x):
- print(x)
- time.sleep(0.5)
- return 666
- @test
- def func2(x,y):
- print(x,y)
- time.sleep(0.6)
- return 333
- print(func1('a'))
- print(func2('b',[1,2,3,4]))
- #结果
- a
- 执行效率为0.5004842281341553
- 666
- b [1, 2, 3, 4]
- 执行效率为0.6007628440856934
- 333
写到现在才终于把整个迭代器搞明白了,哎,以后的工作就是伴随着装饰器啊
2.7 装饰器的总结
对上述所有的迭代器总结下就是下面这个例子了
- def test(f):
- def inner(*args,**kwargs):
- #对函数进行装饰之前的代码
- ret = f(*args,**kwargs)#返回值
- #对函数进行装饰之后的代码
- return ret#将函数的返回值返回出去
- return inner
- #装饰器的基本结构就是这个啦。。。
- 装饰器:装饰器的本质是闭包,而且装饰器其实就是个函数而已。
装饰器:在不改变原函数调用方式上,给原函数增加了一些额外的功能。登录验证,写日志,执行效率等等。
3.延伸:代码开发的开放封闭原则
开放封闭原则:
对拓展开放的:
我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。
所以我们必须允许代码扩展、添加新功能。
对修改是封闭的:
就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,
如果这个时候我们对其进行了修改,很有可能影响其他已经在使用该函数的用户。
装饰器就是开放封闭原则完美的体现。
python中的闭包和装饰器的更多相关文章
- 21.python中的闭包和装饰器
python中的闭包从表现形式上定义(解释)为:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure). 以下说明主要针对 python ...
- Python 中的闭包与装饰器
闭包(closure)是函数式编程的重要的语法结构.闭包也是一种组织代码的结构,它同样提高了代码的可重复使用性. 如果在一个内嵌函数里,对在外部函数内(但不是在全局作用域)的变量进行引用,那么内嵌函数 ...
- 轻松理解python中的闭包和装饰器 (下)
在 上篇 我们讲了python将函数做为返回值和闭包的概念,下面我们继续讲解函数做参数和装饰器,这个功能相当方便实用,可以极大地简化代码,就让我们go on吧! 能接受函数做参数的函数我们称之为高阶函 ...
- 轻松理解python中的闭包和装饰器(上)
继面向对象编程之后函数式编程逐渐火起来了,在python中也同样支持函数式编程,我们平时使用的map, reduce, filter等都是函数式编程的例子.在函数式编程中,函数也作为一个变量存在,对应 ...
- 聊聊Python中的闭包和装饰器
1. 闭包 首先我们明确一下函数的引用,如下所示: def test1(): print("--- in test1 func----") # 调用函数 test1() # 引用函 ...
- python中的闭包与装饰器
#原创,转载请留言联系 装饰器的本质就是闭包,所以想知道装饰器是什么,首先要理解一下什么是闭包. 闭包 1. 外部函数返回内部函数的引用.2. 内部函数使用外部函数的变量或者参数. def outer ...
- python中函数总结之装饰器闭包
1.前言 函数也是一个对象,从而可以增加属性,使用句点来表示属性. 如果内部函数的定义包含了在外部函数中定义的对象的引用(外部对象可以是在外部函数之外),那么内部函数被称之为闭包. 2.装饰器 装饰器 ...
- python基础16_闭包_装饰器
不了解是否其他语言也有类似 python 装饰器这样的东西. 最近才发现ECMAScript6也是有生成器函数的,也有 yield generator 装饰器的基础知识是闭包: # 闭包:嵌套函数, ...
- 第十七篇 Python函数之闭包与装饰器
一. 装饰器 装饰器:可以拆解来看,器本质就是函数,装饰就是修饰的意思,所以装饰器的功能就是为其他函数添加附加功能. 装饰器的两个原则: 1. 不修改被修饰函数的源代码 2. 不修改被修饰函数的调用方 ...
随机推荐
- Java序列化和反序列化,你该知道得更多
序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程.在序列化期间,对象将其当前状态写入到临时或持久性存储区.以后,可以通过从存储区中读取或反序列化对象的状态,重新 ...
- linux添加C#运行环境
linux是不带C#的运行环境的,同样的还有.NET. 有一个叫做Mono的很好用http://www.go-mono.com/,有给docker,而且有环境的选择,要注意. 安好后有给样例的程序,编 ...
- 监控mysql
Mysql服务器监控 管理MySql服务器属于应用程序监控范畴.这是因为绝大多数性能参数是有MySql软件产生的,而不属于主操作系统的一部分. 如当前所提到的,应该总是先监控基础操作系统,然后监控My ...
- 【Config】类库读取自己的配置文件,配置文件的扩展
我们在项目中一般都是使用统一的项目文件配置,所有的配置和自定义的字段都写在一个web.config或者App.config文件中.一般平时我们也没有发现问题,确实这么写没有问题,但是就是如果写的多了就 ...
- webpack入门教程--1
首先说什么是webpack:Webpack 是一个前端资源加载/打包工具.它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源. 然后因为webpack有不同的版本,所以 ...
- [JS设计模式]:工厂模式(3)
简单工厂模式是由一个方法来决定到底要创建哪个类的实例, 而这些实例经常都拥有相同的接口. 这种模式主要用在所实例化的类型在编译期并不能确定, 而是在执行期决定的情况. 说的通俗点,就像公司茶水间的饮料 ...
- 在虚拟机中搭建qduoj(二)——安装OJ
在上一章中,我们已经做好了准备工作,现在,正式开始搭建OJ. 可以先看看官方文档: https://github.com/QingdaoU/OnlineJudgeDeploy/tree/2.0 运行p ...
- ArcGIS 网络分析[3] 发布NAServer到ArcGIS for Server(以Server 10.4为例)
前阵子对ArcGIS API For JavaScript的网络分析有兴趣,但是不知道其数据是如何获取的. 查阅API知道,AJS的网络分析只有三个功能:最短路径(RouteTask).最近设施点(C ...
- Fragment与Activity的接口回调
这里说一个官方推荐的写法: private OnFragmentInteractionListener mListener; @Override public void onAttach(Contex ...
- Netty学习笔记(一) 实现DISCARD服务
官方那个给出的介绍是:Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客户端程序.然后我们简单理解 ...