闭包 python_根据面试题谈谈 Python 闭包
题目:
1.什么是闭包?闭包的定义?
2.手写一个简单的闭包
3.变量作用域规则与 nonlocal 关键字?
4.闭包的应用
答案要点:
1.首先,我们要了解变量作用域,上代码:# 示例一
def test1(a):
print(a)
print(b) # 当函数执行到这一步时会报错。
# NameError: global name 'b' is not defined
test1(1)
# 示例二
b = 6
def test2(a):
print(a)
print(b)
test2(1) # 1 6
# 示例三
b = 6
def test3(a):
print(a)
print(b) # 当函数执行到这一步仍然会报错
# UnboundLocalError: local variable 'b' referenced before assignment
b = 9 # 比示例二多了一行赋值
test3(1)
学过其他语言,比如 Java ,对示例三的结果会比较惊讶,在 Java 中类似的情况,不会报错,会引用外部的全局变量,而如果在内部重新赋值后,再次使用则会用局部变量的值。而在 Python 中情况则不一样,它在编译函数时,发现对 b 有赋值的操作,它判定 b 是一个局部变量,所以在打印 b 时,它会去查询局部变量b,发现并没有赋值,所以会抛出异常。
引用《流畅的Python》中对此的解释:这不是缺陷,而是设计选择:Python 不要求声明变量,但是假定在函数定义体中赋值的变量是局部变量。这比 JavaScript 的行为要好多了,JavaScript 也不要求声明变量,但是如果忘记把变量声明为局部变量(使用var),可能会在不知情的情况下获取全局部变量。
上段话第一次看可能会有点不明白,其实简单来说,Python 就是这样设计的,它认为在函数体中,如果对变量有赋值操作,则证明这个变量是一个局部变量,并且它只会从局部变量中去读取数据。这样设计可以避免我们在不知道的情况下,获取到全局变量的值,从而导致一些错误数据的出现。
至于解决方法,就是使用 global 关键字,来说明我们使用的是 全局变量 。示例如下:b = 6
def test4(a):
print(a)
global b # 1
print(b) # 6
b = 9
print(b) # 9
test4(1)
2.闭包的定义:简单来说,闭包的概念就是当我们在函数内定义一个函数时,这个内部函数使用了外部函数的临时变量,且外部函数的返回值是内部函数的引用时,我们称之为闭包。有点绕,上代码:# 一个简单的实现计算平均值的代码
def get_avg():
scores = [] # 外部临时变量
def inner_count_avg(val): # 内部函数,用于计算平均值
scores.append(val) # 使用外部函数的临时变量
return sum(scores) / len(scores) # 返回计算出的平均值
return inner_count_avg # 外部函数返回内部函数引用
avg = get_avg()
print(avg(10)) # 10
print(avg(11)) # 10.5
...
3.nonlocal 关键字。上面的代码,有一个小缺陷,有很多重复的计算,当我们传入一个新的值想要得到新的平均值时,其他前一次的总和是可以通过外部临时变量存储的。于是我们很自然的想到下面的代码:# 一个简单的实现计算平均值的代码改进版一
def get_avg():
scores = 0 # 将外部临时变量由 list 改为一个 整型数值
count = 0 # 同时新增一个变量,记录个数
def inner_count_avg(val): # 内部函数,用于计算平均值
scores += val # 使用外部函数的临时变量
count += 1
return scores / count # 返回计算出的平均值
return inner_count_avg # 外部函数返回内部函数引用
avg = get_avg()
print(avg(10)) # 报错
...
这里报错的原因,请看第 1 点:变量的作用规则。因为 scores += val ,其实就是 scores = scores + val,有了赋值操作,则认为 scores 是局部变量了。而我们也没办法使用 global 关键字,因为此时 scores 和 count 是定义在 get_ave 函数内的,它们俩也是一个局部变量。而为什么我们使用 list 时,没有出现这个问题呢?也是很好理解的,因为我们使用的是 list.append() 方法,它没有赋值操作。你可以简单认为,可变对象(即我们可以通过调用自身一些方法去做增删改操作且变量地址值不变)不存在此问题,而不可变对象则会有。
在 Python 3 中引入了一个关键词 nonlocal 解决了这一个问题:# 一个简单的实现计算平均值的代码改进版二
def get_avg():
scores = 0 # 将外部临时变量由 list 改为一个 整型数值
count = 0 # 同时新增一个变量,记录个数
def inner_count_avg(val): # 内部函数,用于计算平均值
nonlocal count, scores
scores += val # 使用外部函数的临时变量
count += 1
return scores / count # 返回计算出的平均值
return inner_count_avg # 外部函数返回内部函数引用
avg = get_avg()
print(avg(10)) # 报错
你也许会说,那在 Python 2 的环境下应该怎么解决呢?恩,其实也是有办法的,思路就是将不可变对象变为可变对象即可。代码如下:# -*- coding:utf-8 -*-
class Score:
pass
def get_avg():
s = Score() # 使用类对象
s.scores = 0.0 # 注意 Python 2 中整数除法是舍弃小数的,所以要定义为浮点数
s.count = 0
def inner_get_avg(val):
s.count += 1
s.scores += val
return s.scores / s.count
return inner_get_avg
avg = get_avg()
print(avg(10)) # 10.0
print(avg(11)) # 10.5
4.闭包的应用:首先是装饰器,装饰器就是通过修改被装饰函数,来达到增加新功能的作用。当我们在内部函数去修改被装饰函数时,大部分情况都会使用到闭包。简单示例:def decorator(func): # 外部函数的局部变量 func
def wrapper(*args, **kwargs): # 接受被包装函数传入过来的参数
return func(*args, **kwargs) # 使用外部函数的局部变量 func
return wrapper
@decorator
def basic_func(name):
print 'my name is', name
# 等价于
decorator_func(func)
另外一个应用由之前求平均值的示例也可以看出来,可以在重复计算时提高效率。其次还有一个比较重要的应用场景,就是利用“惰性求值”这一特性,这一点在 Django 的 QuerySet 里有体现。当我们利用 ORM 去做 SQL 查询时,很多时候会根据不同的判断条件,去加 filter,加 filter 的时候并没有真正做查询,在最终获取结果的时候才真正执行了查询。这一点有兴趣的可以去看下源码。
闭包 python_根据面试题谈谈 Python 闭包相关推荐
- [转载] 根据Python常见面试题来谈谈 Python 闭包
参考链接: Python闭包 这里根据我们平常见到的一些Python常见面试题来跟大家说一下关于Python闭包的相关问题! 题目: 1.什么是闭包?闭包的定义? 2.手写一个简单的闭包 3.变量作用 ...
- python闭包两种写法_浅析Python闭包
一.什么是闭包python 在介绍闭包概念前,咱们先来看一段简短的代码数组 def sum_calc(*args):defwrapper(): sum=0for n inargs: sum+=n;re ...
- python闭包的应用场景_聊聊Python闭包-阿里云开发者社区
Python中的闭包不是一个一说就能明白的概念,但是随着你往学习的深入,无论如何你都需要去了解这么一个东西. 闭包的概念 我们尝试从概念上去理解一下闭包. 在一些语言中,在函数中可以(嵌套)定义另一个 ...
- pprint python_让我们来谈谈python中的prettyprint和pprint
当你开始学习python编程的时候,你做的第一件事是什么? 相信我们都已经通过"Hello World"程序开始了我们的python之旅.在python中,它可以在一行中完成: p ...
- Python 闭包 (closure)深入解析
1. 闭包介绍 闭包概念: 在一个内部函数中,对外部作用域的变量进行引用,并且一般外部函数的返回值为内部函数,那么内部函数就被认为是闭包. 闭包作用: 1.装饰器 2.面向对象 3.实现单利模式 闭包 ...
- python闭包的应用场景_简单谈谈Python中的闭包
Python中的闭包 前几天又有人留言,关于其中一个闭包和re.sub的使用不太清楚.我在脚本之家搜索了下,发现没有写过闭包相关的东西,所以决定总结一下,完善Python的内容. 1. 闭包的概念 首 ...
- 谈谈Groovy闭包
A closure is a function with variables bound to a context or environment in which it executes. 概述 闭包 ...
- 深入理解Python闭包概念
闭包并不只是一个Python中的概念,在函数式编程语言中应用较为广泛.理解python中的闭包一方面是能够正确的使用闭包,另一方面可以好好体会和思考闭包的设计思想. 1.概念介绍 首先看一下维基上对闭 ...
- python闭包主要解决什么问题_关于python中闭包的总结
1.闭包的概念 首先,仍然从闭包是什么讲起,来看下维基百科上给出的解释: 一脸懵? 通过PYTHON语言解释一下,闭包,简而言之,给你一个函数,调用该函数后,它并没有返回一个值,而是返回了另一个函数, ...
最新文章
- 如何在Node JS中卸载NPM模块?
- Tiles Framework
- 关于JAVA项目中CLASSPATH路径详解
- UPS故障案例集(一)
- 黑马程序员pink老师前端入门教程,零基础必看的JavaScript基础语法视频教程(DOM)
- springboot+maven实现模块化编程
- Spring Cloud笔记-Maven构建父子项目
- Asp.net MVC4 Knockoutjs BootStrap Ace NinJect Jqgrid sqlserver2008
- 网信集团:一直在正常运营 高管被带走消息不实
- 2019年8月1日星期四(数据结构)
- Spring Boot 分页插件PageHelper
- php完整系统由哪几部分,一个完整的物联网系统由哪些部分组成,各有什么功能?...
- csrss.exe和winlogon.exe引起cpu居高不下的解决办法
- MES系统是什么?MES系统的主要功能是什么?看完本文就知道
- 使用 Arduino 烧录全新的 ATmega328P
- android反编译apk命令,APK反编译关键命令及步骤
- matlab fig图片读取,从Matlab .fig文件中读取数据,并重新绘图
- 漂亮的聊天软件网页HTML5模板源码下载
- 想知道如何将PDF合并成一个?这里有三个简单的方法分享
- Vue+style 动态样式绑定(收藏图标)
热门文章
- 从图(Graph)到图卷积(Graph Convolution):漫谈图神经网络模型 (一)
- BZOJ4627 前缀和 + 权值线段树
- Spring cloud开发内存占用过高解决方法
- 如何开启开源之旅(一)
- sublime text插件emmet自定义模板
- Delphi XE7 用indy开发微信公众平台(3)- 验证消息真实性
- VSS 数据库地址批量更改器 - VSS Database Changer
- Script - MapSubString()使用
- 8-1-Filter过滤器
- 电脑备忘录软件测试自学,软件测试经验和教训分享.pdf