day13 闭包及装饰器
"""
今日内容:
1、函数的嵌套定义及必包
2、global 与 nonlocal 关键字
3、开放封闭原则及装饰器
""" """
一、函数的嵌套定义及闭包
-- 在一个函数中定义另一个函数的过程叫做函数的嵌套定义 -- 为什么要使用函数的嵌套定义?
-- 在一个函数中要是用另一个函数中的变量,就在原函数中嵌套定义这个新函数
-- 但是嵌套定义后函数内部的函数就只能在函数的原函数的内部使用,在函数外部不能直接访问该函数
-- 如果想要访问新函数,可以将新函数作为返回值传递到函数的内部
-- 这样,在函数的外部重新定义一个与新函数重名的变量就可以像内部函数一样进行加()使用 -- 闭包(closure):在函数内部定义的,在函数外部也可以进行调用的函数就叫做闭包函数。
""" """
二、global 与 nonlocal 关键字
-- global 关键字
-- 当想要将函数内部的变量升级为全局变量时,就可以使用global关键字
-- 使用方法为:在函数内部需要升级变量作用域的变量上方加入 global 变量名
def fn1():
num = 10
-- 如果想要将num的作用域提升为全局,那么就需要在函数的上方加入 global关键字
def fn1():
global num
num = 10
-- 这样函数num的作用域就是全局了 -- nonlocal 关键字
-- 当只想要将嵌套函数内部的变量提升一个等级,那么就需要使用到nonlocal 关键字,但是使用nonlocal关键字使需要注意两个问题
-- 使用nonlocal关键字提升变量等级时,此关键字必须在父类函数中存在,不存在就会报错
-- 如果要提升变量等级,此变量所在的函数必须有父类函数,如果没有也会报错 -- global 与 nonlocal关键字的使用注意事项: -- 如果想要统一 outer 及 inner中的 num ,那么就将两个 num 都是用global进行声明,而不能使用nonlocal进行链式升级。
num = 0
def outer():
global num
num = 1
def inner():
global num
num = 10
print(num)
inner()
print(num)
outer()
print(num) """ """
三、开放封闭原则及装饰器
-- 开放封闭原则
-- 开放原则:可以为代码添加新的功能
-- 封闭原则:
-- 不能修改源代码
-- 不能修改调用方式 -- 装饰器
装饰器是一个满足开放封闭原则的闭包的应用 -- 多装饰器的加载顺序:
-- 先进后出,后进先出
"""
# 装饰器的推导:
"""
想要给原函数添加新功能,但是不能修改原函数及函数的调用方式
原函数:
def fn1():
print("插花") 需要添加的功能: 观赏 """ # 闭包函数的推导 """
def fn1():
num = 10 def fn2():
print(num)
""" # 第一种方法:将fn1的num作为返回值传递给外部,再用名字为num的变量进行接收 --> 这样只是有一个找了一个重名的变量,并不是原来的变量
# 第二种方法:使用global关键字将num变为全局变量,这样,如果全局变量中有num这个变量,会重新赋值
# 第三种方法:将函数fn2定义到函数fn1的内部,这样fn2就可以使用fn1的变量了 # 综上使用第三种方法进行验证
"""第一步:想要在一个函数内部使用另一个函数的内部变量 --> 将新函数放入到原函数的内部
def fn1():
num = 10
def fn2():
print(num)
-- 使用这种方法时,弊端就是不能在全局中调用fn2函数,只能在fn1中调用
""" """ 第二步:想要在全部中访问函数fn2:可以将fn2作为fn1函数的返回值,在外界接收后记性调用 def fn1():
num = 10
def fn2():
print(num)
return fn2 # res = fn1()
fn2 = fn1()
fn2() -- 使用这种方法可以将函数的返回值使用变量进行接收,变量可以使用任意合法的变量名接收,可以使用n,m等名字,也可以使用fn2进行接收
-- 当使用fn2进行接收时,此时使用fn2()就可以执行,跟直接调用原来的函数相同。这样fn2既可以使用num 又可以在外界进行调用。
-- 这个在函数内部定义的函数就叫做闭包函数(closure)
""" # 装饰器推导
"""第一步:在函数的内部调用原来的函数 def fn2():
print("观赏")
fn1() fn1 = fn2
fn1() # RecursionError: maximum recursion depth exceeded while calling a Python object -- 这样看似可以使用,但是在调用时会报错,原因是函数执行过程中,执行时先到 def fn2() --> fn1 = fn2 此时 fn1中内存地址与fn2中相同 -->
fn1()实际上就是运行fn2() --> 进入到fn2函数内部 --> 打印 插花 --> 运行fn1(),但是此时fn1=fn2,还是会调用fn2函数 --> 死循环 """ """第二步:对第一步进行更新,将fn1首先赋值给第三方变量temp,此时就不会进入死循环
temp = fn1 def fn2():
print("观赏")
temp() fn1 = fn2
fn1() -- 此时就是装饰器
-- 但是此装饰器分为了三部分,temp = fn1 ,def fn2 ,fn1=fn2,如果在三部分中间不小心对temp进行了重新赋值,就会破坏这个装饰器
-- 为了时装饰器更加的统一,需进行进一步进化
""" """第三步:将装饰器的三部分进化为两部分
-- 由于fn2函数的内部需要使用temp,此时可以将这两部分封装为一个函数
def outer():
temp = fn1
def fn2():
print("观赏")
temp()
return fn2 fn1 = outer()
fn1() -- 此时,装饰器已经进一步完善,但是如果fn1是有参数及返回值的呢?需要将函数的参数及返回值传递到装饰器内部
""" """第四步:给原函数添加参数 def fn1(name):
print("插花%s"%name) def outer():
temp = fn1 def fn2(name):
print("观赏")
temp(name) return fn2 fn1 = outer()
name = input("花: ")
fn1(name) -- 函数还是有可能也有返回值,需要将返回值传递到装饰器的内部
""" """第五步:给装饰器传递返回值 def fn1(name):
print("插花%s"%name)
return name def outer():
def fn2(name):
print("观赏")
res = temp(name)
return res
return fn2 fn1 = outer()
name = input("花: ")
print(fn1(name)) -- 此时,函数既有参数也有返回值了,已经无限接近于完美了,但是还有一个小问题,这个装饰器只能给固定的一个函数fn1使用(添加新功能),但是如果想给
其它的函数也使用这个装饰器呢? """ """第六步:将装饰器变成可以通用的装饰器
-- 如果想要将装饰器变为通用的装饰器,此时有两个方面需要修改,一个是被装饰的函数本身,另一个是函数的参数列表不固定 def fn1(name):
print("插花%s"%name)
return name def outer(func):
def fn2(*args,**kwargs):
print("观赏")
res = func(*args,**kwargs)
return res
return fn2 fn1 = outer(fn1)
name = input("花: ")
print(fn1(name)) -- 函数本身的变化可以将函数通过outer传入
-- 函数的参数列表的变化,可以使用可变长形参进行传递(*args,**kwargs) """ """
根据上述步骤,可以总结一个装饰器的公式: def outer(func):
def inner(*args,**kwargs):
pass # 要添加的代码块
res = func(*args,**kwargs)
pass # 需要添加的功能代码
return res
return inner """ """第七步:在python中提供了一种语法糖,可以将整个装饰器与被装饰的函数统一为一个整体
-- 这种语法就是使用 @装饰器名称 添加到被装饰函数的上方
-- 使用这种语法糖需要将装饰器函数写到被装饰函数的上方 """
day13 闭包及装饰器的更多相关文章
- python闭包与装饰器
转自小马哥: 闭包和装饰器充分体现了Python语法糖的优雅感觉. 在本文中,我们的实验要完成两个工作,一个是加法,一个是累计调用加法的次数,最普通的Python程序可以这么写: def valida ...
- python之闭包与装饰器
python闭包与装饰器 闭包 在函数内部定义的函数包含对外部的作用域,而不是全局作用域名字的引用,这样的函数叫做闭包函数. 示例: #-------------------------------- ...
- Python编程四大神兽:迭代器、生成器、闭包和装饰器
生成器 生成器是生成一个值的特殊函数,它具有这样一个特点:第一次执行该函数时,先从头按顺序执行,在碰到yield关键字时该函数会暂停执行该函数后续的代码,并且返回一个值:在下一次调用该函数执行时,程序 ...
- python中的闭包和装饰器
重新学习完了函数,是时候将其中的一些重点重新捋一捋了,本次总结的东西只有闭包和装饰器 1.闭包 闭包是python函数中的一个比较重要功能,一般闭包都是用在装饰器上,一般学完闭包就会去学习装饰器,这俩 ...
- python 闭包和装饰器
python 闭包和装饰器 一.闭包闭包:外部函数FunOut()里面包含一个内部函数FunIn(),并且外部函数返回内部函数的对象FunIn,内部函数存在对外部函数的变量的引用.那么这个内部函数Fu ...
- Python核心编程的四大神兽:迭代器、生成器、闭包以及装饰器
生成器 生成器是生成一个值的特殊函数,它具有这样的特点:第一次执行该函数时,先从头按顺序执行,在碰到yield关键字时该函数会暂停执行该函数后续的代码,并且返回一个值:在下一次调用该函数执行时,程 ...
- 21.python中的闭包和装饰器
python中的闭包从表现形式上定义(解释)为:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure). 以下说明主要针对 python ...
- Python 中的闭包与装饰器
闭包(closure)是函数式编程的重要的语法结构.闭包也是一种组织代码的结构,它同样提高了代码的可重复使用性. 如果在一个内嵌函数里,对在外部函数内(但不是在全局作用域)的变量进行引用,那么内嵌函数 ...
- 关于python的闭包与装饰器的实验
首先看闭包,在嵌套函数内添加返回值,可以通过外部函数读取内部函数信息 #encoding=utf-8 #闭包应用 #先定义闭包函数,并使用 def outer(func): def inner(): ...
随机推荐
- maven导入外部jar包的方法
maven的导入外部jar包的方法(前提还有外部jar包) 1.问题: 在maven添加依赖包时,添加不成功,可以选择通过外部命令导入到仓库里. 2.命令:(在Dos命令行) mvn install: ...
- EXT 设置编辑框为只读
Ext.getCmp("processResult").setReadOnly(ture); //processResult是属性的id,setReadOnly(ture)设置 ...
- asp.net 文件分片上传
最近在研究文件上传,里面的门道还是挺多的,网上大多数文章比较杂乱,代码都是片段,对于新手小白来说难度较高,所以在此详细写一下今天看到的一个demo,关于文件分片上传的. <!DOCTYPE ht ...
- KVM宿主机上虚拟机动态添加新磁盘
(1)KVM宿主机查看运行的虚拟机 $ virsh list --all (2)将qcow2的磁盘移动到/var/lib/libvirt/images/,比如为centos.qcow2 (3)进入/e ...
- linux安装redis操作
redis官网地址:http://www.redis.io/ 最新版本:2.8.3 在Linux下安装Redis非常简单,具体步骤如下(官网有说明): 1.下载源码,解压缩后编译源码. $ wget ...
- Django ORM多表操作
多表操作 创建模型 实例:我们来假定下面这些概念,字段和关系 作者模型:一个作者有姓名和年龄. 作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息.作者详情模型和作者模型之间是一对 ...
- SpringBoot+Redis整合
SpringBoot+Redis整合 1.在pom.xml添加Redis依赖 <!--整合Redis--> <dependency> <groupId>org.sp ...
- Pyhon进阶9---类的继承
类的继承 基本概念 定义 格式如下 继承中的访问控制 class Animal: __CNOUT = 0 HEIGHT = 0 def __init__(self,age,weight,height) ...
- Vue.js 2.x笔记:基本语法(2)
1. Vue实例及选项 1.1 创建Vue实例(new Vue instance) 每个Vue Application必须创建一个root Vue Instance. <script> v ...
- SqlMapConfig.xml 的配置
jdbc.properties :数据库连接的配置 jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://192.168.181.135:33 ...