重新学习完了函数,是时候将其中的一些重点重新捋一捋了,本次总结的东西只有闭包和装饰器

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中的闭包和装饰器的更多相关文章

  1. 21.python中的闭包和装饰器

    python中的闭包从表现形式上定义(解释)为:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure). 以下说明主要针对 python ...

  2. Python 中的闭包与装饰器

    闭包(closure)是函数式编程的重要的语法结构.闭包也是一种组织代码的结构,它同样提高了代码的可重复使用性. 如果在一个内嵌函数里,对在外部函数内(但不是在全局作用域)的变量进行引用,那么内嵌函数 ...

  3. 轻松理解python中的闭包和装饰器 (下)

    在 上篇 我们讲了python将函数做为返回值和闭包的概念,下面我们继续讲解函数做参数和装饰器,这个功能相当方便实用,可以极大地简化代码,就让我们go on吧! 能接受函数做参数的函数我们称之为高阶函 ...

  4. 轻松理解python中的闭包和装饰器(上)

    继面向对象编程之后函数式编程逐渐火起来了,在python中也同样支持函数式编程,我们平时使用的map, reduce, filter等都是函数式编程的例子.在函数式编程中,函数也作为一个变量存在,对应 ...

  5. 聊聊Python中的闭包和装饰器

    1. 闭包 首先我们明确一下函数的引用,如下所示: def test1(): print("--- in test1 func----") # 调用函数 test1() # 引用函 ...

  6. python中的闭包与装饰器

    #原创,转载请留言联系 装饰器的本质就是闭包,所以想知道装饰器是什么,首先要理解一下什么是闭包. 闭包 1. 外部函数返回内部函数的引用.2. 内部函数使用外部函数的变量或者参数. def outer ...

  7. python中函数总结之装饰器闭包

    1.前言 函数也是一个对象,从而可以增加属性,使用句点来表示属性. 如果内部函数的定义包含了在外部函数中定义的对象的引用(外部对象可以是在外部函数之外),那么内部函数被称之为闭包. 2.装饰器 装饰器 ...

  8. python基础16_闭包_装饰器

    不了解是否其他语言也有类似 python 装饰器这样的东西. 最近才发现ECMAScript6也是有生成器函数的,也有 yield  generator 装饰器的基础知识是闭包: # 闭包:嵌套函数, ...

  9. 第十七篇 Python函数之闭包与装饰器

    一. 装饰器 装饰器:可以拆解来看,器本质就是函数,装饰就是修饰的意思,所以装饰器的功能就是为其他函数添加附加功能. 装饰器的两个原则: 1. 不修改被修饰函数的源代码 2. 不修改被修饰函数的调用方 ...

随机推荐

  1. 如何在React项目中直接使用WebAssembly

    前言 自从入坑WebAssembly以来,躺了很多坑,也浏览了很多资料,都没有看到很多能够直接在前端项目中使用WebAssembly的例子.即使有,我自己按照介绍的步骤一步一步来, 也会报各种错误,官 ...

  2. RabbitMQ消息队列(十)-高可用集群部署实战

    前几章讲到RabbitMQ单主机模式的搭建和使用,我们在实际生产环境中出于对性能还有可用性的考虑会采用集群的模式来部署RabbitMQ. RabbitMQ集群基本概念 Rabbit模式大概分为以下三种 ...

  3. [一]FileDescriptor文件描述符 标准输入输出错误 文件描述符

    文件描述符   当应用程序请求打开或者操作文件时,操作系统为应用程序设置一张文件列表,具体的实现形式此处不深入说明 操作系统会提供给你一个非负整数,作为一个索引号,它的作用就像地址或者说指针或者说偏移 ...

  4. SpringCloud应对高并发的思路

    一.Eureka的高可用性 Eureka下面的服务实例默认每隔30秒会发送一个HTTP心跳给Eureka,来告诉Eureka服务还活着,每个服务实例每隔30秒也会通过HTTP请求向Eureka获取服务 ...

  5. Java提高班(四)面试必备—你不知道的数据集合

    导读:Map竟然不属于Java集合框架的子集?队列也和List一样属于集合的三大子集之一?更有队列的正确使用姿势,一起来看吧! Java中的集合通常指的是Collection下的三个集合框架List. ...

  6. haproxy使用演示--技术流ken

    haproxy简介 HAProxy提供高可用性.负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费.快速并且可靠的一种解决方案.基于合理的配置及优化,完全可以实现单机支持数 以万计的并 ...

  7. 研发团队如何写好API接口文档

    导读 背景 痛点在哪? 为什么要写接口文档? API规范 接口工具 总结 背景        随着业务的发展,支撑组的项目也是越来越多.同时,从整个支撑组项目架构体系(含运维和运营体系),我们对系统业 ...

  8. OO第一单元作业总结

    oo第一单元的作业是对多项式的求导.下面就是对三次作业分别进行分析. 第一次作业 分析 第一次作业相对来讲比较简单,甚至不用面向对象的思想都能十分轻松的完成(实际上自己就没有使用),包含的内容只有常数 ...

  9. 【学习笔记】tensorflow实现一个简单的线性回归

    目录 准备知识 Tensorflow运算API 梯度下降API 简单的线性回归的实现 建立事件文件 变量作用域 增加变量显示 模型的保存与加载 自定义命令行参数 准备知识 Tensorflow运算AP ...

  10. Mybatis框架基础支持层——日志模块(8)

    前言: java开发中常用的日志框架有Log4j,Log4j2,Apache Commons Log,java.util.logging,slf4j等,这些工具对外的接口不尽相同.为了统一这些工具的接 ...