1. 闭包
首先我们明确一下函数的引用,如下所示:
def test1(): print("--- in test1 func----") # 调用函数 test1() # 引用函数 ret = test1 print(id(ret)) print(id(test1)) #通过引用调用函数 ret()
运行结果:
--- in test1 func---- 140212571149040 140212571149040 --- in test1 func----
以y=kx+b为例,请计算一条线上的某个点,即给x值计算出y值。下面以这个例子引出闭包的概念。
方法1
# 第1种 k = 1 b = 2 y = k*x+b # 缺点:如果需要多次计算,那么就的写多次y = k*x+b这样的式子
方法2
# 第2种 def line_2(k, b, x): print(k*x+b) line_2(1, 2, 0) line_2(1, 2, 1) line_2(1, 2, 2) # 缺点:如果想要计算多次这条线上的y值,那么每次都需要传递k,b的值,麻烦
方法3
# 第3种: 全局变量 k = 1 b = 2 def line_3(x): print(k*x+b) line_3(0) line_3(1) line_3(2) k = 11 b = 22 line_3(0) line_3(1) line_3(2) # 缺点:如果要计算多条线上的y值,那么需要每次对全局变量进行修改,代码会增多,麻烦
这里引申一下,关于全局变量,要是直接读取,不修改的话,是不用加global的。
而且所谓的修改,指的是地址变了,假如我指向的是一个列表,指向没变,列表中的内容改变了,也不用加global的。
我们看一下下面的例子:
a = 100 b = ‘chenchi‘ c = [1, 2, 3] def func(): print(‘a的值:{},a的地址:{}‘.format(a, id(a))) print(‘b的值:{},b的地址:{}‘.format(b, id(b))) print(‘c的值:{},c的地址:{}‘.format(c, id(c))) def func2(): global a global b a += 1 b += ‘ccc‘ # 这里c不用声明global,c的地址没有发生变化 c.append(4) if __name__ == ‘__main__‘: func() func2() func()
运行结果:
列表的地址没变,不用加global。
方法4
# 第4种:缺省参数 def line_4(x, k=1, b=2): print(k*x+b) line_4(0) line_4(1) line_4(2) line_4(0, k=11, b=22) line_4(1, k=11, b=22) line_4(2, k=11, b=22) # 优点:比全局变量的方式好在:k, b是函数line_4的一部分 而不是全局变量,因为全局变量可以任意的被其他函数所修改 # 缺点:如果要计算多条线上的y值,那么需要在调用的时候进行传递参数,麻烦
方法5
# 第5种:实例对象 class Line5(object): def __init__(self, k, b): self.k = k self.b = b def __call__(self, x): print(self.k * x + self.b) line_5_1 = Line5(1, 2) # 对象.方法() # 对象() line_5_1(0) line_5_1(1) line_5_1(2) line_5_2 = Line5(11, 22) line_5_2(0) line_5_2(1) line_5_2(2) # 缺点:为了计算多条线上的y值,所以需要保存多个k, b的值,因此用了很多个实例对象, 浪费资源
关于__call__()的用法:
方法6
采用闭包的方式,什么是闭包呢?
在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包。
如下所示:
# 第6种:闭包 def line_6(k, b): def create_y(x): print(k*x+b) return create_y line_6_1 = line_6(1, 2) line_6_1(0) line_6_1(1) line_6_1(2) line_6_2 = line_6(11, 22) line_6_2(0) line_6_2(1) line_6_2(2)
闭包,红色部分return的不能加(),不加()是函数引用,否则就应该是函数的返回值。
在上面的例子中,函数line_6与变量k,b构成闭包,闭包具有提高代码可复用性的作用。
由于闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存,但是相对于实例对象来说,已经好多了。
思考:函数、匿名函数、闭包、对象 当做实参时 有什么区别?
1. 匿名函数能够完成基本的简单功能,传递是这个函数的引用 只有功能。
2. 普通函数能够完成较为复杂的功能,传递是这个函数的引用 只有功能。
3. 闭包能够将较为复杂的功能,传递是这个闭包中的函数以及数据,因此传递是功能+数据。
4. 对象能够完成最为复杂的功能,传递是很多数据+很多功能,因此传递是功能+数据。
修改外部函数中的变量
x = 300 def outer(): x = 200 def inner(): nonlocal x # global x print(‘---1---x=%d‘ % x) x = 100 print(‘---1---x=%d‘ % x) return inner t1 = outer() t1()
注意,这是python3,输出结果如下:
如果把nonlocal改成global,第一个x就变成300了。
2. 装饰器
原文地址:https://www.cnblogs.com/DarrenChan/p/10346935.html
时间: 2024-11-05 19:38:31