python之函数作用域、嵌套以及闭包

我们首先回忆一下Python代码运行的时候遇到函数是怎么做的,从Python解释器开始执行之后,就在内存中开辟里一个空间,每当遇到一个变量的时候,就把变量名和值之间对应的关系记录下来,但是当遇到函数定义的时候,解释器只是象征性的将函数名读如内存,表示知道这个函数存在了,至于函数内部的变量和逻辑,解释器根本不关心。

  等执行到函数调用的时候,Python解释器会再开辟一块内存来储存这个函数里面的内容,这个时候,才关注函数里面有哪些变量,而函数中的变量回储存在新开辟出来的内存中,函数中的变量只能在函数内部使用,并且会随着函数执行完毕,这块内存中的所有内容也会被清空。

我们给这个‘存放名字与值的关系’的空间起了一个名字-------命名空间。

代码在运行伊始,创建的存储“变量名与值的关系”的空间叫做全局命名空间;

在函数的运行中开辟的临时的空间叫做局部命名空间。

 

在python中,名称空间三种:

  • 全局名称空间
  • 局部名称空间(临时)
  • 内置名称空间




作用域:

  • 全局作用域:作用于全局名称空间 内置名称空间
  • 局部作用域:作用于局部名称空间(临时)


取值顺序:就近原则,单向从小到大范围
局部名称空间 ---> 全局名称空间 ---> 内置名称空间


加载顺序
内置名称空间 ---> 全局名称空间(当程序执行时) ---> 局部名称空间(当函数调用的时候)

 

 

 

局部名称空间 对全局名称空间的变量可以引用,但是不能改变。

如果你在局部名称空间对一个变量进行修改,那么解释器会认为你的这个变量在局部中已经定义了。

global

  • 1.在局部名称空间声明一个全局变量
  • 2.在局部名称空间可以对全局变量进行修改


实际中
不常用

nonlocal

  • 相当于子函数对父函数的变量进行修改。
  • 此变量不能是全局变量
  • # 在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,
  • # 并且引用的哪层,从那层及以下此变量全部发生改变。
# global
    # 1,在局部名称空间声明一个全局变量。
# def func2():
#     global name
#     name = 'alex'
# func2()
# print(name)

    # 2,在局部名称空间可以对全局变量进行修改。
# count = 1
# def func1():
#     global count
#     count = count + 1
#     print(count)
# func1()
# print(count)
global
# nonlocal
# def func1():
#     count = 666
#     def func2():
#         print(count)
#     func2()
# func1()
nonlocal

 

函数嵌套

def func1():
    count = 666
    def inner():
        print(count)
        def func2():
            nonlocal count
            count += 1
            print('func2',count)
        func2()
        print('inner',count)
    inner()
    print('func1',count)
func1()
#  666  func2 667  inner 667  func1 667

  

函数名的应用:

  • 1. 函数名就是函数的内存地址
  • 2. 函数名可以做为变量
  • 3. 函数名可以做为函数的参数
  • 4. 函数名可以当作函数的返回值
  • 5. 函数名可以做为容器类类型的元素


像上面的函数名这种,叫第一类对象

  • 1. 可在运行期创建
  • 2. 可用作函数参数或返回值
  • 3. 可存入变量的实体。
 1. 函数名就是函数的内存地址
# def func1():
#     print(666)
#
# print(func1)  #<function func1 at 0x0000028BEC62C1E0>

# 2. 函数名可以做为变量
# f1 = func1
# f1()


# 3. 函数名可以做为函数的参数
# def func1():
#     print(666)
#
# def func2(x):
#     x()  # func1()
#
# func2(func1)

# 4. 函数名可以当作函数的返回值
# def wraaper():
#     def inner():
#         print('----inner  ')
#     return inner
#
# ret = wraaper()  # inner
# ret()
#
# def func2():
#     print('in the func2')
#
# def func3(x):
#     print('in the func3') # x = func2
#     return x
#
# f1 = func3(func2)  # func2
# f1()

# 5. 函数名可以做为容器类类型的元素
# def func1():
#     print('in func1')
#
# def func2():
#     print('in func2')
#
# def func3():
#     print('in func3')
#
# l1 = [func1, func2, func3, ]
# for i in l1:
#     i()

# 像上面的函数名这种,叫第一类对象

  

globals() 返回全局变量的一个字典
locals() 返回当前位置的局部变量的字典

# globals()  locals()

# def func1():
#     pass
# print(globals())
# print(locals())


def func1():
    a = 2
    b = 3
    print(globals())
    print(locals())
func1()

  

闭包: 内层函数对外层函数的变量(非全局变量)的引用,并返回, 这样就形成了闭包。

闭包的作用:
当程序执行时,遇到了函数执行,他会在内存中开辟一个空间,局部名称空间。如果这个函数内部形成了闭包,
那么他就不会随着函数的结束而立马消失。

 

# def wrapper():
#     name = 'alex'
#     def inner():
#         print(name)
#     print(inner.__closure__)  # 判断是否闭包(<cell at 0x00000181FD0ED8E8: str object at 0x00000181FD00CE68>,)
#                                     # 不是闭包返回None
#     inner()
#     return inner
#
# wrapper()

name = 'alex'
def wrapper(n):
    # 相当于 n = 'alex'
    def inner():
        print(n)
    print(inner.__closure__)  # 闭包
    inner()
    return inner

wrapper(name)

  

 

posted @ 2018-08-16 16:32  3DX2Y  阅读(259)  评论(0编辑  收藏  举报