type
status
date
slug
summary
tags
category
icon
password
前言
今日在更新程序的时候遇到了个问题。
如何生成多语言的菜单,创建并绑定相应的回调函数?
生成菜单自然是很简单的,一个for循环就好了,但是生成相应函数就???
正文
在解决以下事件的过程中,又思考得出了别的内容。
续:前言事件
情况如下,现有语言列表及两个业务方法。
- 最初的想法如下(方法一):
但是菜单无论如何点击,都会设置成 ‘cn’。(失败)
这是因为,创建回调函数(lambda表达式)时,以引用的方式将 lang 变量传入了函数;而 lang 变量是随着for循环改变的,而for循环最后一个值为 ‘cn’。(见languages list)
- 略加改进之后(方法二):
本以为,将操作再作为函数封装起来,然后再将 lang 变量传入参数 x(参数变量是临时的)即可解决问题(规避引用)。但是,结果与前面相同。(失败)
- 正解操作:
来看看这个方法与前面两种方法的区别:
简单来说,方法一与方法二是一致的,想法都是创建一个带占位符(菜单参数)的回调函数,然后在回调函数里设置语言(for循环中的 lang 变量)。
而正解方法三的想法,则是创建一个生成回调函数的函数,然后将 lang 变量注入生成函数,最终返回设置各个语言的回调函数。(感觉有点反过来了)
由于定义了生成函数的函数,所以此处可对其进行复用。(减少创建次数)
至此,问题解决。
什么是闭包
在前面的事件中,思考方法二的代码要如何修改时,请教了友人 Musoucrow,其提到了闭包这一知识点。(似乎前面根据参数生成函数这种操作就是闭包???)
经过一番查阅资料发现:闭包是由函数及其相关引用环境组合而成的实体;闭包就是指有权访问另一个函数作用域中的变量的函数。(???)
来看下面一个例子:
这是一个简单的求和函数。
假如有以下要求:求和函数非立即运算,而是在后面再调用进行运算。
那么就需要将函数拆分成两部分:一是将被求和的变量初始化(生成环境),二是计算的过程。
如下代码所示:
此时,调用 sum 函数生成的函数 f 和 g 都引用了被求和的 list - 变量 l,且变量 l 在两个函数间相互独立。
也就是在生成函数时,同时创建了一套变量的环境。(可以理解成方法中的静态变量)
据我所理解,闭包就是一个可以根据参数生成的,独立环境(一个或多个静态变量)与函数的集合体。
修改“静态变量”
这里是一个加法函数的生成函数,逻辑上看并没有什么问题。
当运行时会提示:
这时,如果要修改“静态变量”(外函数的变量),需要使用 nonlocal 关键字。
由此可见,函数 f 与函数 g 之间,各拥有着一套独立的环境。
闭包与装饰器
在查阅资料的过程中,见到一种说法:闭包用于实现装饰器。
猛然想起,python里面的语法糖,装饰器!
计时器
以下是一个业务函数,为了检测其运行时间,通常会这么做:
装饰器,可用于对已有的函数进行包装,将某函数(如xxx)传入装饰器函数内,生成新的函数,并覆盖原函数。
具体看代码。
常见的装饰器有如 @property、@staticmethod 等,其本质应该还是闭包(创建函数及其独立环境)。
带参装饰器
函数是可以具备参数的,所以装饰器也是同样道理可以带参。
带参装饰器,只需要在原有装饰器函数再进行一次套皮即可。