函数对象&闭包函数

函数对象

python的世界,一切皆对象,函数也不例外。

函数对象可以像普通变量那样被引用、被存放在容器数据中当元素,作为一个函数的实参、也可以作为函数的返回值。

函数被引用

函数名可以赋值给新的变量名,相当于起别名,别名加括号同样可以调用函数。

def add(x, y):
    print(x+y)
func = add
func(3,4)		# 等同于 add(x, y); 类似变量的赋值引用

函数做容器对象的元素

# 函数名相当于一个变量名,容器保存这个函数的内存地址,就类似列表内套一个列表对象

函数做实参

# 将函数做另一个函数的实参,相当于这个函数的返回结果作为另一个函数的实参

def func(x):
    return x + 1

def add(x, func):
    print(func(x))

add(3, func)	# 打印:4

函数做返回值

def add(x, y):
    return x+y

def foo():
    return add

func = foo()	# 相当于 func = add
func(3, 4)		# x相当于 add(3, 4)

闭包函数

在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。

闭&包

基于函数对象的概念,可以将函数返回到任意位置去调用,但作用域的关系是在定义完函数时就已经被确定了的,与函数的调用位置无关。

也就是说函数被当做数据处理时,始终以自带的作用域为准。若内嵌函数包含对外部函数作用域(而非全局作用域)中变量的引用,那么该’内嵌函数’就是闭包函数,简称闭包(Closures)。

def outer(x):
    def inner():
        return x+1	# 此时 inner是闭包函数(引用了外层函数作用域的变量)
    return inner

x = 10
def outer():
    def inner():
        return x+1	# 此时,inner不是闭包函数(没有引用外层函数作用域的变量)
    return inner

判断闭包的方法

# 方法1:是否引用外层函数作用域中的变量
# 方法2:通过函数的closure属性,查看到闭包函数所包裹的外部变量。不是闭包该值为None

# func.__closure__		# 元组形式
# func.__closure__[0].cell_contents	 # 查看具体引用的第一个值

“闭”代表函数是内部的,“包”代表函数外’包裹’着对外层作用域的引用。

因而无论在何处调用闭包函数,使用的仍然是包裹在其外层的变量。

闭包的用途

为函数体传值(传参)。

def outer(s):
    def inner():
        print(s)
       return inner

func = outer('hello world')
func()				# 打印: 'hello world'
func()				# 打印: 'hello world'

一次传参,后续使用无须再传参 。闭包函数的这种特性有时又称为惰性计算。

变形装饰器(下一节再细讲)

补充

>>> def outer(x): 
...     def inner_reads():
...         # Will return outer's 'x'.
...         return x
...     def inner_writes(y):
...         # Will assign to a local 'x', not the outer 'x'
...         x = y
...     def inner_error(y):
...         # Will produce an error: 'x' is local because of the assignment,
...         # but we use it before it is assigned to.
...         tmp = x
...         x = y
...         return tmp
...     return inner_reads, inner_writes, inner_error
... 
>>> inner_reads, inner_writes, inner_error = outer(5)
>>> inner_reads()
5
>>> inner_writes(10)
>>> inner_reads()
5
>>> inner_error(10)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 11, in inner_error
UnboundLocalError: local variable 'x' referenced before assignment

上述函数 inner_writes(10)无法修改变量x,是因为内修改的仅仅是inner_writes局部名称空间内的变量x,而inner_reads()度的还是外层函数outer的x。如果非要修改可以使用'nonlocal'声明x,但不能使用'global'。

posted @ 2020-03-18 16:18  the3times  阅读(210)  评论(0编辑  收藏  举报