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、闭包的创建

闭包就是函数和所引用环境变量的组合体,闭包不等于函数,而只是形式上返回函数而已。既然闭包分为两个部分,那么其创建过程可以分为:

  1. 打包环境变量
  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、何为重载

重载一般为了解决两个问题:

  1. 可变参数类型
  2. 可变参数个数

此外,还有一个基本的设计原理:仅仅当两个函数除了参数类型和参数个数不同以外,其功能是完全相同的,此时才使用函数重载,如果两个函数功能其实不相同那么不应该使用重载,而是应当使用一个名字不同的函数。
例如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不需要重载的原因

  1. 当函数功能相同,参数类型不同时。由于python是动态语言(详情看我之前写的文章《Python语言基础考察一》),所以不需要担心传入的参数的类型的问题。
  2. 函数功能相同,个数不同时。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不需要重载就讲到这里啦~