参考:
Python-闭包详解
Python的可变类型与不可变类型
官方Resolution of names
官方教程 - 函数的定义
前言:
lua中也有闭包,但一知半解,因为遇到了python的装饰器,需要闭包的基础,再理解一遍
什么是闭包:
有一个很基础的结构
定义一个函数A,在函数A中在定义一个函数B,A返回函数B名
你可以看出调函数A()其实就是在调用内部函数B
如果把40行的()去掉结果是怎样
这时候要借助print,打印发现其实返回的是B函数的地址,A()()相当于是B()
如果这里认为闭包就是返回内部函数,那就太小看闭包了,这个只是闭包的其中一个特点
现在加上 函数普遍要用的参数 和 函数普遍要用的局部变量
会发现函数B中可以调用A中的参数,na 和 pa
也就是函数B绑定了两个变量na,pa
这就是闭包的另一个特性:绑定外部的变量到自己作用域(但不作为自己作用域的局部变量,所以有个拗口的名字,叫做非局部变量)
总结:
闭包:1.调用内部函数 同时 2.绑定外部变量作为自己环境
真的就这么简单吗?
1.写一个算 本金+利息 的闭包,利息为0.2
这样写是没啥问题,但是有时候你会这么写
还没运行前就发现n报红了,强行运行后发现
直接翻译:错误的意思是赋值前引用的局部变量’n’
出现错误官方解释,也就是局部变量在引用前没有绑定个值
n为啥会变成局部变量?局部变量是哪里产生的?
函数执行的时候会引入函数局部变量的新符号表,更详细的说,函数中的所有变量赋值都将值存储在本地符号表中,函数中变量引用的时候会按照顺序从不同的符号表中查找这个变量
1.本地符号表
2.封闭函数(闭包)的本地符号表
3.全局符号表
4.内置名称表
现在引出一个新的问题,符号表是什么?看一下Python sysmtable 使用
回到错误的地方n += n * rate
在调用这个函数的时候,创建新的符号表,有赋值则把n变量放到新的符号表中,在n * rate时候引用是发现本地符号表中的n并没有赋值,则报错
要改变非局部变量,有两种方法:
1.用可变类型变量为外部参数2.用python提供了一个关键字nonlocal
内部函数调用外部变量时
如果外部变量是不可变参数,则内部函数中不能改变外部变量
如果外部变量时可变参数,则内部函数中可以改变外部变量
在内部函数中对外部变量加上关键字 nonlocal ,在内部函数中可以改变外部变量
2.容易犯错的地方
这里5次print 会输出几?
这里要记住,调用顺序,闭包的内部函数,只有在你调用的时候才会运行,在运行add函数的时候都是在给内部函数制造环境,再保存个test()地址,方便之后调用找到地方,不会进入14行给i赋值,只有运行到19行中才会进入15行test()函数中,所以里面的i是4
把代码打入到pycharm中,Debug模式下,看的很清楚