闭包 python_python中的闭包

本文探讨了Python中的函数作为对象的概念,展示了如何通过`__call__`方法使对象可调用。接着解释了闭包的概念,它是如何提高代码复用性的,并通过例子展示了不同方式计算线性方程的值,强调了闭包在减少参数传递和增强代码移植性方面的作用。最后,介绍了如何在Python 2和3中修改闭包内的数据,包括使用`nonlocal`关键字和通过列表存储变量进行模拟修改。
摘要由CSDN通过智能技术生成

1. 函数

python中的一切皆对象,函数也是一个对象,如下:

In [44]: def test():

....: pass

....:

In [45]: type(test)

Out[45]: function

In [46]: type(test.__call__)

Out[46]: method-wrapper

如果一个对象能使用函数调用的方式调用(即xxx()的方式),那么这个对象需要定义一个__call__的魔法属性,如下:

In [47]: class Foo(object):

....: def __call__(self):

....: print("__call__")

....:

In [48]: f = Foo()

In [49]: f()

__call__

在Foo对象中定义了一个__call__的魔法属性,创建了Foo的一个实现对象f,并使用调用:f(),如果传递一个函数对象的引用,那么通过这个函数的应用就能调用这个函数。

2. 什么是闭包?

假如要计算反正y=ax+b的值,有如下几种做法:

2.1 直接计算

# 第1种

a = 1

b = 2

y = k*x+b

缺点:如果需要多次计算,那么就的写多次y = a*x+b这样的式子

2.2 使用函数

# 2. 使用函数

def test(a, b, x):

print(a * x + b)

test(1, 2, 1)

test(1, 2, 10)

test(2, 4, 1)

test(2, 4, 10)

缺点: 如果要多次计算某条y=ax+b上的值,需要多次传入a,b的值

2.3 使用全局变量

# 3. 使用全局变量

a = 1

b = 2

def test(x):

print(a * x + b)

test(1)

test(10)

a = 2

b = 4

test(1)

test(10)

缺点:如果要计算多条y=ax+b上的值,需要多次修改全局变量a,b的值,麻烦

2.4 使用缺省参数

# 4. 使用缺省参数

def test(x, a=1, b=2):

print(a * x + b)

test(1)

test(10)

test(1, a=2, b=4)

test(10, a=2, b=4)

优点:相比第三种方式,a和b是默认参数的一部分,不是全局变量

缺点:如果计算多条y=ax+b的值,需要多次传入a,b的值麻烦

2.5 使用实例对象

# 5. 使用实例对象

class Test(object):

def __init__(self, a, b):

self.a = a

self.b = b

def __call__(self, x):

print(self.a * x + self.b)

t1_2 = Test(1, 2)

t1_2(1)

t1_2(10)

t2_4 = Test(2, 4)

t2_4(1)

t2_4(10)

缺点,为了计算y的值,需要保存a,b的值,用了实例对象,浪费资源

2.6 使用闭包

# 6. 使用闭包

def test(a, b):

def create_y(x):

print(a * x + b)

return create_y

t1_2 = test(1, 2)

t1_2(1)

t1_2(10)

t2_4 = test(2, 4)

t2_4(1)

t2_4(10)

函数create_y与变量a,b构成闭包。在创建闭包的时候,我们通过test的参数a,b说明了这两个变量的取值,这样,我们就确定了函数的最终形式(y = x + 2和y = 2x + 4)。我们只需要变换参数a,b,就可以获得不同的直线表达函数。由此,我们可以看到,闭包也具有提高代码可复用性的作用。

如果没有闭包,我们需要每次创建直线函数的时候同时说明a,b,x。这样,我们就需要更多的参数传递,也减少了代码的可移植性。

关于闭包,维基百科的定义如下:

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

百度百科:

闭包是可以包含自由(未绑定到特定对象)变量的代码块;这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量)。“闭包” 一词来源于以下两者的结合:要执行的代码块(由于自由变量被包含在代码块中,这些自由变量以及它们引用的对象没有被释放)和为自由变量提供绑定的计算环境(作用域)。在 Scala、Scheme、Common Lisp、Smalltalk、Groovy、JavaScript、Ruby、 Python和Lua,objective c 等语言中都能找到对闭包不同程度的支持。

在编程领域我们可以通俗的说:子函数可以使用父函数中的局部变量,这种行为就叫做闭包!

3. 修改闭包中的数据

python3中:

x = 100

def test1():

x = 101

def test2():

nonlocal x

print("--1--x: %s" % x)

x = 102

print("--2--x: %s" % x)

return test2

test1()()

像在函数中修改全局变量一样,在python3中修改闭包中的数据需要使用nonlocal,就像上面那么:nonlocal x

python2中:

def test1():

x = 101

temp_list = [x]

def test2():

print("--1--x: %s" % temp_list[0])

temp_list[0] = 102

print("--2--x: %s" % temp_list[0])

return test2

test1()()

由于python2没有像python3中的nonlocal,要在python2中修改闭包中的数据,只能在一个list中保存要修改的变量,直接对该列表中对应的数据进行修改就能完成伪修改。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值