python 中的闭包与重载
- python 中的闭包
- 1、何为闭包
- 2、闭包的创建
- python 的重载
- 首先python不需要重载,这个一会儿再说
- 1、何为重载
- 2、python不需要重载的原因
python 中的闭包
1、何为闭包
先看一下闭包效应:
def make():
x = [1,2]
return lambda: print(x)
a = make()
a()
如果不考虑闭包效应,这段代码很有问题。因为x生命周期是make栈帧,调用结束之后理应被销毁,匿名函数显然无法构成引用。然而事实是所返回的匿名函数依然可以访问x变量,这就是闭包效应。闭包会延长环境变量的生命周期,应谨慎使用。
在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。闭包可以用来在一个函数与一组“私有”变量之间创建关联关系。在给定函数被多次调用时,这些私有变量能够保持其持久性。 ——《维基百科》
例如:
def make_printer(msg):
def printer():
print msg # 夹带外部变量
return printer # 返回的是函数
printer = make_printer('Foo!')
printer()
再例如:
def make():
x = 100
def test(): print(x)
return test
2、闭包的创建
闭包就是函数和所引用环境变量的组合体,闭包不等于函数,而只是形式上返回函数而已。既然闭包分为两个部分,那么其创建过程可以分为:
- 打包环境变量
- 将环境变量作为参数,新建要返回的函数对象
Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:06:47) [MSC v.1914 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> def make():
... x = 100
... def test(): print(x)
... return test
...
>>> import dis
>>> dis.dis(make)
2 0 LOAD_CONST 1 (100)
2 STORE_DEREF 0 (x) #保存在DEREF
3 4 LOAD_CLOSURE 0 (x) #闭包环境变量
6 BUILD_TUPLE 1
8 LOAD_CONST 2 (<code object test)
10 LOAD_CONST 3 ('make.<locals>.test')
12 MAKE_FUNCTION 8 #创建函数时包含闭包函数
14 STORE_FAST 0 (test)
4 16 LOAD_FAST 0 (test)
18 RETURN_VALUE
Disassembly of <code object test at 0x01792180, file "<stdin>", line 3>:
3 0 LOAD_GLOBAL 0 (print)
2 LOAD_DEREF 0 (x) #从DEREF载入闭包环境变量
4 CALL_FUNCTION 1
6 POP_TOP
8 LOAD_CONST 0 (None)
10 RETURN_VALUE
>>>
python 的重载
首先python不需要重载,这个一会儿再说
1、何为重载
重载一般为了解决两个问题:
- 可变参数类型
- 可变参数个数
此外,还有一个基本的设计原理:仅仅当两个函数除了参数类型和参数个数不同以外,其功能是完全相同的,此时才使用函数重载,如果两个函数功能其实不相同那么不应该使用重载,而是应当使用一个名字不同的函数。
例如Java的重载:
public class Test{
public void a(int i,String j){
}
public class a(int i,String j){
}
}
- 说明:在Test类中有两个同名的方法。在调用方法时,如果传入的第一个参数类型为int,第二个参数类型为String,则自动调用第一个方法a。如果传入的第一个参数为String类型,第二个参数类型为int,则自动调用第二个方法a。
2、python不需要重载的原因
- 当函数功能相同,参数类型不同时。由于python是动态语言(详情看我之前写的文章《Python语言基础考察一》),所以不需要担心传入的参数的类型的问题。
- 函数功能相同,个数不同时。python 可以使用*args 接收不定个数参数,假如还需要传入键值对(例如:a = b)时,python 还可以使用 **kwargs 来接收。
实例:
>>> def test1(x,*args):
... print(x,args)
...
>>> def test2(x,y,*args,**kwargs):
... print(x,y,args,kwargs)
...
>>> test1(1,2,3,4,5,6)
1 (2, 3, 4, 5, 6)
>>> test2(1,2,'12','23',a=4,b=5)
1 2 ('12', '23') {'a': 4, 'b': 5}
>>>
python不需要重载就讲到这里啦~