python:闭包

​ 假设我们需要做一个题目,是求y=kx+b这个一元一次函数在多个x上的值。

1.前言

第一种方法:

# -*- coding: utf-8 -*-
# @Author  : summer
k = 1
b = 2
x = 0
print(k * x + b)
x = 1
print(k * x + b)
x = 2
print(k * x + b)

这个是最平常的一种写法,即直接定义一个k和一个b,然后写一个x,接着直接打印出y的值

其实这个方法的缺点也可以看出–》代码冗余。那么代码冗余的话我们可不可以用函数解决呢?

第二种:函数法

# -*- coding: utf-8 -*-
# @Author  : summer
k = 1
b = 2
def create(x):
    print(k * x + b)  
create(1)

函数的方法虽然可以,但是如果代码过多,或者在create函数后面还有许多的函数,就可能导致全局变量k和b被修改导致结果出错,那有没有什么办法可以把变量存起来,让自己单独使用呢?没错就是面向对象方法

第三种:面向对象法

# -*- coding: utf-8 -*-
# @Author  : summer
class Create:
	def __init__(self, k, b):
		self.k = k
		self.b = b
        
	def __call__(self, x, *args, **kwargs):
		print(self.k * x + self.b)
c1 = Create(1, 2)
c1(1)

同样,上面的方法虽然可以把全局变量放入自己内部,但别忘了,创建对象时不知有现在所看到的两个魔法方法,每个对象默认调用object,因此你创建一个对象就会多出好多个没有的魔法方法,因此还有没有更好的方法呢?他来了—-闭包

第四种:闭包

# -*- coding: utf-8 -*-
# @Author  : summer
def test(k, b):
	def create(x):
		print(k * x + b)
	return create

t = test(1, 2)
t(1)

上面这种方法就是闭包,即函数里面再嵌套一层函数,并且最外层的函数返回值时内层函数的引用

2.什么是闭包

# 定义一个函数
def test(number):

    # 在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包
    def test_in(number_in):
        print("in test_in 函数, number_in is %d" % number_in)
        return number+number_in
    # 其实这里返回的就是闭包的结果
    return test_in


# 给test函数赋值,这个20就是给参数number
ret = test(20)

# 注意这里的100其实给参数number_in
print(ret(100))

#注 意这里的200其实给参数number_in
print(ret(200))

运行结果:

in test_in 函数, number_in is 100
120

in test_in 函数, number_in is 200
220

3.看一个闭包的实际例子:

def line_conf(a, b):
    def line(x):
        return a*x + b
    return line

line1 = line_conf(1, 1)
line2 = line_conf(4, 5)
print(line1(5))
print(line2(5))

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

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

注意点:

由于闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存

4.修改外部函数中的变量

def counter(start=0):
    def incr():
        nonlocal start
        start += 1
        return start
    return incr

c1 = counter(5)
print(c1())
print(c1())

c2 = counter(50)
print(c2())
print(c2())

print(c1())
print(c1())

print(c2())
print(c2())

这里使用一个nonlocal来声明start。和global差不多就是作用范围不同。

5.思考闭包与其他函数的区别

1.匿名函数能够完成基本的简单功能。传递的是这个参数的引用因此只有功能。
2.普通函数能够完成较为复杂的功能。传递的是这个函数的引用因此也只有功能。
3.闭包能后完成较为复杂的功能。传递的是这个闭包中的函数以及数据因此传递的是功能和数据。
4.对象能后完成最复杂的功能。传递的是很多数据+功能因此传递的是功能和数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值