【Python】Python3.7.3 - 闭包Closure技术

文章目录

  • Wikipedia对“一等函数”的定义
  • Wikipedia对嵌套函数的定义
  • Wikipedia对闭包的定义
  • 对闭包的理解
  • Python的嵌套函数
  • Python闭包的例子
  • Python闭包的实用例子

本文仅基于自己对闭包技术的理解,并非官方权威文档。所以可能存在技术错误,欢迎留言指正。

先做点准备活动,看看一等函数的定义。

Wikipedia对“一等函数”的定义

In computer science, a programming language is said to have first-class functions if it treats functions as first-class citizens. This means the language supports passing functions as arguments to other functions, returning them as the values from other functions, and assigning them to variables or storing them in data structures. Some programming language theorists require support for anonymous functions (function literals) as well. In languages with first-class functions, the names of functions do not have any special status; they are treated like ordinary variables with a function type. The term was coined by Christopher Strachey in the context of “functions as first-class citizens” in the mid-1960s.

在计算机科学中,一个程序设计语言被称为具有”一等函数“,如果该语言把函数当作“一等公民”。这意味着这种语言支持a) 把函数当作参数传递给其他函数,b) 从其他函数中返回函数,c)把函数赋值给变量或者存储在数据结构中。某些程序设计语言理论学者还要求支持匿名函数(函数文本形式)。对于支持一等函数的语言,函数名本身没有任何状态;他们被当作常规的变量,只是变量类型是“函数”。“一等函数/一等公民”这个词是由Christopher Strachey在1960年代中期的论文“functions as first-class citizens”中创造的。

从这个定义可以看出,C语言是具有一等函数的语言。通过函数名,即函数地址/指针,可以把函数传递给其他函数,从其他函数中返回函数地址,把函数指针保存在变量或数据结构中。

同理,Python也是具有一等函数的语言。而且Python还支持匿名函数。

有了一等函数,哪谁是二等函数呢?有些程序设计语言支持的嵌套函数可以认为程序设计语言中的二等公民。

Wikipedia对嵌套函数的定义

In computer programming, a nested function (or nested procedure or subroutine) is a function which is defined within another function, the enclosing function. Due to simple recursive scope rules, a nested function is itself invisible outside of its immediately enclosing function, but can see (access) all local objects (data, functions, types, etc.) of its immediately enclosing function as well as of any function(s) which, in turn, encloses that function. The nesting is theoretically possible to unlimited depth, although only a few levels are normally used in practical programs.

在程序设计语言中,嵌套函数(或者嵌套过程,或者子例程)是定义在另一个函数中的函数,外层的这个函数被称为包含函数(enclosing function)。根据简单递归规则,嵌套函数对除包含函数之外的外层函数不可见,但是可以访问所有外层函数的本地变量。这种嵌套原则理论上可以支持无线深度的嵌套,尽管实际实现中支持少数几层嵌套。

早期的ALGOL,Simula 67和PASCAL,以及现代的动态语言和函数式语言都支持嵌套函数;但是C以及类C的语言都不支持嵌套函数。

从这个定义可以看出,嵌套函数的确是二等公民,对外基本上不可见,更别提把它传递个其他函数或者保存在变量中了。

但是有时候,我们的确需要把内层函数导出来,或者封装某些内层函数来使用,这时候怎么办呢?这就需要闭包技术来支持了。

Wikipedia对闭包的定义

https://en.wikipedia.org/wiki/Closure_(computer_programming)#History_and_etymology

In programming languages, a closure, also lexical closure or function closure, is a technique for implementing lexically scoped name binding in a language with first-class functions. Operationally, a closure is a record storing a function together with an environment. The environment is a mapping associating each free variable of the function (variables that are used locally, but defined in an enclosing scope) with the value or reference to which the name was bound when the closure was created. Unlike a plain function, a closure allows the function to access those captured variables through the closure’s copies of their values or references, even when the function is invoked outside their scope.

在程序设计语言中,闭包(closure),也被称为词法闭包(lexical closure)或者函数闭包(function closure),是一种技术,用于在语言中实现“到一等函数的词法范围内的名称绑定”。是实际实现中,闭包是一个记录,存储一个函数以及一个环境。环境是一个映射,当闭包被创建时,将函数的每个自由变量(free variable,本地使用的变量,但是并未定义在封闭范围里)关联到自由变量名表达的值或者引用。不像简单的纯函数,闭包通过拷贝值或者引用从而允许函数访问它“捕获的变量”,即使函数在定义范围外被调用。

对闭包的理解

  1. 闭包是一种程序设计技术
  2. 闭包是一种命名绑定机制
  3. 闭包是一个记录
  4. 闭包记录一个映射关系
  5. 闭包记录访问的非本地变量的值或者引用
  6. 闭包有被记录的值或者引用的副本
  7. 闭包可以在定义域之外访问

Python的嵌套函数

定义在一个函数中的函数被称为嵌套函数。嵌套函数可以访问定义在封闭范围(enclosing scope)内的变量。 这意味着,在Python中,嵌套函数可以访问外层函数中定义的变量。对于嵌套函数而言,这些变量是非局部变量,而是定义在封闭范围内的变量。参看下面这个例子:

# 例子来源:https://www.geeksforgeeks.org/python-closures/
# Python program to illustrate 
# nested functions 
def outerFunction(text): 
	# text变量是outerFunction的本地变量
	text = text 

	def innerFunction(): 
		# 在嵌套函数中,依然可以访问text变量
		print(text) 

	# 执行嵌套函数
	innerFunction() 

if __name__ == '__main__': 
	outerFunction('Hey!') 

Python闭包的例子

Python的闭包技术允许把嵌套函数传到外部世界,或者封装外部世界的函数,添加新的功能。

# 例子来源:https://www.geeksforgeeks.org/python-closures/
# Python program to illustrate 
# closures 
def outerFunction(text): 
	text = text 

	def innerFunction(): 
		print(text) 

	# 返回嵌套函数,可供外部世界调用
	# 假如Python没有闭包技术,则只能执行嵌套函数;而不能返回嵌套函数
	return innerFunction # Note we are returning function WITHOUT parenthesis 

if __name__ == '__main__': 
	# 在调用一等函数outerFunction时,Python的闭包技术实现
	# 会创建text的拷贝,将来供嵌套函数使用
	myFunction = outerFunction('Hey!') 
	
	# 在调用这个嵌套函数时,InnerFunction函数可以访问text的拷贝。
	myFunction() 

Python闭包的实用例子

我们有两个函数add()与sub(),现在想要对这个两个函数增加日志功能。
有了闭包功能,我们把这两个函数名作为参数传递给logger(),内层嵌套函数打印日志后,执行/保存传递进来的函数,然后将嵌套函数返回。

# 例子来源:https://www.geeksforgeeks.org/python-closures/
# Python program to illustrate 
# closures 
import logging 
logging.basicConfig(filename='example.log', level=logging.INFO) 


def logger(func): 
	# 定义嵌套函数
	def log_func(*args): 
		# 日志输出
		logging.info( 
			'Running "{}" with arguments {}'.format(func.__name__, args)) 
		# 执行func,打印结果
		print(func(*args)) 
	# Necessary for closure to work (returning WITHOUT parenthesis) 
	return log_func			 

# 需要封装的外部世界函数
def add(x, y): 
	return x+y 

def sub(x, y): 
	return x-y 

add_logger = logger(add) 
sub_logger = logger(sub) 

add_logger(3, 3) 
add_logger(4, 5) 

sub_logger(10, 5) 
sub_logger(20, 10) 

你可能感兴趣的:(Python,闭包,一等公民,一等函数,嵌套函数)