Python之函数进阶-闭包原理
闭包
- 自由变量:未在本地作用域中定义的变量,例如定义在内层函数外的外层函数的作用域中的变量
- 闭包:就是一个概念,出现在嵌套函数中,指的是内层函数引用到了外层函数的自由变量,就形成了闭包。很多语言都有这个概念,最熟悉的就是JavaScript
def inc():
c = [0] # 自由变量
def inner():
c[0] += 1 # 此处+=的对象是列表中的地址引用
return c[0]
return inner
# 定义一个函数,inner中c[0] += 1,是否可以修改inc中c变量呢?
foo = inc()
print(1, foo())
print(2, foo())
# 执行结果是可以修改的,因为inner中修改的是列表中的引用地址。
# 返回结果:1 1
# 返回结果:2 2
c = 100
print(foo())
# 定义一个c=100的变量,然后在执行foo(),得到的结果是3,因为c变量是global全局的,print打印foo()函数,用的是函数内的变量,又执行一个所以是3.
# 返回结果:3
def a():
x = [1]
return id(x)
# 定义一个函数a,在函数体中定义一个变量,return 这个变量的id内存地址
a()
# 返回结果:4375700544
a()
# 每一次函数执行有关系吗?没有,是完全独立的
# 返回结果:4371940480
def inc():
a = (100,)
c = [0]
print(hex(id(c)))
def inner():
c[0] += 1
print(a)
return c[0]
return inner
foo = inc()
print(foo.__name__, type(foo.__name__))
print(foo.__closure__)
print(1, foo())
print(2, foo())
# inner中用到外层函数的自由变量被用到了,所以__closure__要记住,要不然就成垃圾了
# 返回结果:0x104cf5fc0 # 将10进制转换成16进制
# 返回结果:inner <class 'str'> # foo的名字是inner,类型是str
# 返回结果:(<cell at 0x104a350c0: tuple object at 0x104a35600>, <cell at 0x104a343a0: list object at 0x104cf5fc0>) # 执行closure得到的结果,在closure中记住了c的内存地址
# 返回结果:(100,) # 第一次打印内容
# 返回结果:1 1 # 第一次打印内容
# 返回结果:(100,) # 第二次打印内容
# 返回结果:2 2 # 第二次打印内容