"""
今日内容:
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 闭包及装饰器的更多相关文章

  1. python闭包与装饰器

    转自小马哥: 闭包和装饰器充分体现了Python语法糖的优雅感觉. 在本文中,我们的实验要完成两个工作,一个是加法,一个是累计调用加法的次数,最普通的Python程序可以这么写: def valida ...

  2. python之闭包与装饰器

    python闭包与装饰器 闭包 在函数内部定义的函数包含对外部的作用域,而不是全局作用域名字的引用,这样的函数叫做闭包函数. 示例: #-------------------------------- ...

  3. Python编程四大神兽:迭代器、生成器、闭包和装饰器

    生成器 生成器是生成一个值的特殊函数,它具有这样一个特点:第一次执行该函数时,先从头按顺序执行,在碰到yield关键字时该函数会暂停执行该函数后续的代码,并且返回一个值:在下一次调用该函数执行时,程序 ...

  4. python中的闭包和装饰器

    重新学习完了函数,是时候将其中的一些重点重新捋一捋了,本次总结的东西只有闭包和装饰器 1.闭包 闭包是python函数中的一个比较重要功能,一般闭包都是用在装饰器上,一般学完闭包就会去学习装饰器,这俩 ...

  5. python 闭包和装饰器

    python 闭包和装饰器 一.闭包闭包:外部函数FunOut()里面包含一个内部函数FunIn(),并且外部函数返回内部函数的对象FunIn,内部函数存在对外部函数的变量的引用.那么这个内部函数Fu ...

  6. Python核心编程的四大神兽:迭代器、生成器、闭包以及装饰器

      生成器 生成器是生成一个值的特殊函数,它具有这样的特点:第一次执行该函数时,先从头按顺序执行,在碰到yield关键字时该函数会暂停执行该函数后续的代码,并且返回一个值:在下一次调用该函数执行时,程 ...

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

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

  8. Python 中的闭包与装饰器

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

  9. 关于python的闭包与装饰器的实验

    首先看闭包,在嵌套函数内添加返回值,可以通过外部函数读取内部函数信息 #encoding=utf-8 #闭包应用 #先定义闭包函数,并使用 def outer(func): def inner(): ...

随机推荐

  1. c++ 重点随记

    1.在公有继承中:(1).派生类对象储存了基类的私有成员 (2).派生类对象可以使用基类的方法 (3).基类引用可以引用派生类对象,派生类引用不可以引用基类对象 2.基类引用引用派生类对象时:若基类引 ...

  2. [转帖]rsync简介

    rsync用法详细解释 https://www.cnblogs.com/noxy/p/8986164.html 之前一直使用 scp 现在发现这个命令更好一些. 提要 熟悉 rsync 的功能及其特点 ...

  3. 队列(FIFO)—循环队列、队列的链式存储

    1 队列的定义 队列是只允许在一端(队尾)进行插入操作,而在另一端(队头)进行删除操作的线性表. 2 队列的特点 1)先进先出是队列最大的特点,是应用中非常常见的模型,例如排队: 2)队列也属于线性表 ...

  4. [ffmpeg] 滤波格式协商

    ffmpeg的中滤波器是以帧为原料来进行滤波的,那么自然地就会对帧的格式有所要求,可以说如果滤波器不知道帧的格式,就无法对帧进行处理.在进行视频滤波时,滤波格式指的是视频的像素格式:在进行音频滤波时, ...

  5. 归并排序-JAVA实现

    package com.iloveu.xxx; public class MergeSort { static final int SIZE = 15; static void mergeOne(in ...

  6. (简单)华为Nova青春 WAS-AL00的USB调试模式在哪里开启的流程

    就在我们使用Pc接通安卓手机的时候,如果手机没有开启usb开发者调试模式,Pc则无办法成功检测到我们的手机,在一些情况下,我们使用的一些功能较强的app好比之前我们使用的一个app引号精灵,老版本就需 ...

  7. 洛谷P5119 Convent 题解

    题目 很好想的一道二分题,首先,二分一定满足单调性,而题目中非常明显的就是用的车越多,所用时间越少,所以可以枚举时间,判断是否可以比\(m\)少. 然后在二分时,更是要注意下标的一些问题,也要注意车和 ...

  8. C# 将前端传来的图片文件分别以大图和缩略图保存

    HttpPostedFile pic_upload = Request.Files["file"]; Bitmap bitmap = (Bitmap)System.Drawing. ...

  9. git常用命令介绍

    一,仓库 1. git init    把当前目录变成git可管理得仓库,也就是初始化仓库 2. git add 文件名            在仓库中添加新文件 3. git commit -m & ...

  10. linux服务器上,yum、rpm、源码编译安装及卸载

    源码的编译安装及卸载 源码安装三部曲 1.生成makefile编译文件./configure 一般安装包下面都有一个configure文件,用来生成makefile编译文件常用的参数: --prefi ...