一. 一切皆对象

函数式编程并没有标准定义,如果代码非常繁琐则考虑使用。

学习闭包的概念,不是python独有的。

其他大多数语言中的函数只是一段可执行的代码,并不是对象。

python中的函数是对象,一切皆对象。可以把函数赋值给变量:

a = 1

a = '2'

a = def

甚至可以把函数当作另外一个函数的参数传递或者当成返回值返回,而C#中要封装成委托。

二.什么是闭包:闭包=函数+函数定义时的环境变量

我们尝试从概念上去理解一下闭包。

在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。闭包可以用来在一个函数与一组“私有”变量之间创建关联关系。在给定函数被多次调用的过程中,这些私有变量能够保持其持久性。—— 维基百科

用比较容易懂的人话说,就是当某个函数被当成对象返回时,夹带了外部变量,就形成了一个闭包。

1.

code1

def curve_pre():

    def curve():

        pass

curve()    #找不到,因为curve()的作用域仅限于curve_pre()的内部

code2

def curve_pre():

    def curve():
print('This is a function')         pass     return curve    #函数可以作为结果返回 f = curve_pre()    #函数可以赋值 f()#执行函数,不会报错
#This is a function

code3

def curve_pre():

    a = 25         #局部变量在curve的外部

    def curve(x):  #接受抛物线的x值

        return a * x * x

    return curve    #返回一个函数

f = curve_pre()

print(f(2))         #调用curve()函数

#

code4

a = 10

def f1(x):

    return a * x * x

print(f1(2))

#40         #局部变量找不到会去上一级找

code 3 和 code4 对比

def curve_pre():

    a = 25 #局部变量在curve的外部

    def curve(x): #接受抛物线的x值

        return a * x * x

    return curve #返回一个函数

a = 10     #定义a = 10

f = curve_pre()

print(f(2)) #调用curve()函数

#100        #仍然是a = 25的取值,取得是定义时的环境变量,这就是闭包

函数及其外部环境变量所构成的整体叫做闭包

2.环境变量要在函数外部,但不能是全局变量:

a = 25    #a定义为了全局变量

def curve_pre():

    def curve(x): #接受抛物线的x值

        return a * x * x

    return curve #返回一个函数

a = 10

f = curve_pre()

print(f(2)) #调用curve()函数

#40    #a的值被改变了,因为没有形成闭包

查看:

def curve_pre():

    a = 25 #局部变量在curve的外部

    def curve(x): #接受抛物线的x值

        return a * x * x

    return curve #返回一个函数

a = 10

f = curve_pre()

print(f.__closure__)

print(f.__closure__[0].cell_contents)#取出闭包的环境变量

print(f(2)) #调用curve()函数

#(<cell at 0x0031AAF0: int object at 0x0FF93A80>,)

#25    #这里是a的值

#

三.一个事例看看闭包

1.闭包的意义:闭包保存的是一个环境,把函数现场保存起来了。

闭包 = 函数 + 函数定义时的环境变量(不能是全局变量)

2. 闭包的经典误区      从外层向内层分析

def f1():

    a = 10

    def f2():

        a = 20    #对a重新赋值局部变量,不会影响到外部

        print(a)

    print(a)    #

    f2()    #20 #f1内部调用f2

    print(a)    #

f1()

#

#

#

验证其是不是一个闭包:

1

def f1():

    a = 10

    def f2():

        a = 20

        # print(a)

    #print(a)

    f2()

    #print(a)

f = f1()    #f1是None类型

print(f.__closure__)    #报错

(2)加上返回值,仍然不是闭包函数:

def f1():

    a = 10

    def f2():

        a = 20    #a被认为是一个局部变量了,就不认为是个环境变量了

        return a

    return f2

f = f1()

print(f.__closure__)    #没有__closure__属性

#None

(3)去掉f2()中的赋值后是闭包函数:

def f1():

    a = 10

    def f2():

        #a = 20    #删除a = 20,此时a被python认为是一个局部变量

        return a

    return f2

f = f1()

print(f.__closure__)

#(<cell at 0x02F5AAF0: int object at 0x0FF93990>,)

原因:环境变量不能当作一个变量去赋值,而是一定要去引用外部。

四.出个题,用闭包解决!

闭包不是必不可少的东西,只是可以使你的代码架构更加合理。

题目:

旅行者,x = 0 为起点,没走一步加1,计算出旅行者当前所处的位置。

关键点:每次调用时需要调用上次的结果

1.先用非闭包解决一下

origin = 0

def go(step):

    global origin    #将origin变成全局变量

    new_pos = origin + step

    origin = new_pos  #等号左边的origin被python认识是局部变量

    return origin

print(go(2))

print(go(3))

print(go(6))

#

#

#

2.再用闭包解决一下

origin = 0

def factory(pos):    #工厂模式

    def go(step):

        nonlocal pos #强制声明不是局部变量

        new_pos = pos + step

        pos = new_pos

        return new_pos

    return go

tourist = factory(origin)

print(tourist(2))
print(origin) print(tourist(3)) print(tourist(6)) #
# # #

并没有改变全局变量origin的值

五.小谈函数式编程

  • python和Javascript都会使用闭包。
  • 闭包特点:在一个函数外部间接调用函数内部的变量,从模块级别间接调用局部变量。
  • 极易造成内存泄漏。

闭包的概念

Python3(九) 闭包的更多相关文章

  1. Python3基础 闭包 简单示例

    镇场诗: 诚听如来语,顿舍世间名与利.愿做地藏徒,广演是经阎浮提. 愿尽吾所学,成就一良心博客.愿诸后来人,重现智慧清净体.-------------------------------------- ...

  2. Swift5 语言指南(九) 闭包

    闭包是自包含的功能块,可以在代码中传递和使用.Swift中的闭包类似于C和Objective-C中的块以及其他编程语言中的lambdas. 闭包可以从定义它们的上下文中捕获和存储对任何常量和变量的引用 ...

  3. python3 之 闭包实例解析

    一.实例1: def make_power(y): def fn(x): return x**y return fn pow3 = make_power(3) pow2 = make_power(2) ...

  4. python学习之路 五:函数式编程

    本节重点 掌握函数的作用.语法 掌握作用域.全局变量与局部变量知识 掌握函数名称空间.闭包 一.函数编程基础知识 1.基本定义 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数 ...

  5. Web前端经典面试试题(一)

    本篇收录了一些面试中经常会遇到的经典面试题,并且都给出了我在网上收集的答案.眼看新的一年马上就要开始了,相信很多的前端开发者会有一些跳槽的悸动,通过对本篇知识的整理以及经验的总结,希望能帮到更多的前端 ...

  6. python3.4学习笔记(十九) 同一台机器同时安装 python2.7 和 python3.4的解决方法

    python3.4学习笔记(十九) 同一台机器同时安装 python2.7 和 python3.4的解决方法 同一台机器同时安装 python2.7 和 python3.4不会冲突.安装在不同目录,然 ...

  7. python3.4学习笔记(九) Python GUI桌面应用开发工具选择

    python3.4学习笔记(九) Python GUI桌面应用开发工具选择 Python GUI开发工具选择 - WEB开发者http://www.admin10000.com/document/96 ...

  8. python3 练习题100例 (九)

    题目九:题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?程序分析:兔子的规律为数列1,1,2,3,5 ...

  9. python3 练习题100例 (十九)

    #!/usr/bin/env python3 # -*- coding: utf-8 -*- """练习十九:计算1-2+3...+99中除了88以外所有数的和" ...

随机推荐

  1. 深度学习论文翻译解析(七):Support Vector Method for Novelty Detection

    论文标题:Support Vector Method for Novelty Detection 论文作者:Bernhard Scholkopf, Robert Williamson, Alex Sm ...

  2. JS 通过url地址栏获取html页面名称

    有的时候需要获取页面名称,为此我在这里封装了一个方. 一.分别根据传递不同的参数,获取到html页面的名称. 通过传递参数,获取到html页面的名称:参数params 以下是参数解释说明 (1)par ...

  3. VS2019菜单栏没有团队选项解决方法

    新安装了Visual Studio 2019结果菜单栏没有“团队”菜单,导致没办法连接TFS服务器,查了下网上也并没有对应解决方法(甚至遇见这个问题的都没有/笑哭,所以这个方法写出来也大概没什么用) ...

  4. await Task.Yield()和await Task.CompletedTask有什么不同

    有时候我们在代码中要执行一些非常耗时的操作,我们不希望这些操作阻塞调用线程(主线程)的执行,因为调用线程(主线程)可能还有更重要的工作要做,我们希望将这些非常耗时的操作由另外一个线程去执行,这个时候就 ...

  5. 被裁的第50天,我终于拿到心仪公司Offer

    今天分享的是之前分享文章中被裁的小C,可以看这篇文<寒冬之下,被cai的那些人到底去哪了?>,最近他已经找到心仪公司今日头条Offer,并且即将入职,在应我要求下,他写了篇总结文如下.下文 ...

  6. Codeforces I Wanna Be the Guy 题解

    这道题非常简单,有两种做法: 1. 用一个数组标记是不是每个关卡小X或小Y都可以通过 2. 用set储存小X和小Y能够通过的关卡(set有去重功能),最后判断set的长度是否等于n 因为楼上已经有第一 ...

  7. 【JQ】 validate验证表单时多个name相同的元素的解决办法

    使用jQuery.validate插件http://jqueryvalidation.org/,当节点的name相同时候,脚本特意忽略剩余节点,导致所有相关节点的errMsg都显示在第一个相关节点上. ...

  8. 基于Bootstrap和Knockout.js的ASP.NET MVC开发实战 关于 拦截器的 学习 部分

    先贴一段: 下面贴代码: 上面这段代码呢,有几个点迷糊.可以找找看

  9. [校内训练19_09_05]ca

    题意 对于任意1 ≤k≤N,求有多少个左右区分的恰有k个叶子节点的二叉树,满足对于每个节点要么没有叶子节点要么有两个节点,同时不存在一个叶子节点,使得根到它的路径上有不少于M条向左的边. 答案对998 ...

  10. Android教程2020 - RecyclerView响应点击

    本文介绍RecyclerView设置点击的方法.这里给出比较常见的使用方式. Android教程2020 - 系列总览 本文链接 前面我们已经知道如何用RecyclerView显示一列数据. 用户点击 ...