函数命名空间和作用域

三元运算:

变量= 条件返回True的结果 if 条件 else 条件返回false的结果

# a = 1
# b = 5
# c = a if a>b else b   #三元运算
# print(c)
结果显示: 5

 命名空间和作用域

命名空间

有三种

#内置命名空间 —— python解释器
# 就是python解释器一启动就可以使用的名字存储在内置命名空间中
# 内置的名字在启动解释器的时候被加载进内存里
#全局命名空间 —— 我们写的代码但不是函数中的代码
# 是在程序从上到下被执行的过程中依次加载进内存的
# 放置了我们设置的所有变量名和函数名
#局部命名空间 —— 函数
# 就是函数内部定义的名字
# 当调用函数的时候 才会产生这个名称空间 随着函数执行的结束 这个命名空间就又消失了

三种命名空间之间的加载与取值顺序:


加载顺序:内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)

在正常情况下,直接使用内置的名字,当我们在全局定义了和内置名字空间中同名的名字时,会使用全局的名字

取值:

  在局部调用:局部命名空间->全局命名空间->内置命名空间

       在全局调用:全局命名空间->内置命名空间

命名空间的查找顺序
a) 如果在函数内调用一个变量,先在函数内(局部命名空间)查找,如果找到则停止查找。否则在函数外部(全局命名空间)查找,如果还是没找到,则查找内置命名空间。如果以上三个命名都未找到,则抛出NameError 的异常错误。
b) 如果在函数外调用一个变量,则在函数外查找(全局命名空间,局部命名空间此时不可见),如果找到则停止查找,否则到内置命名空间中查找。如果两者都找不到,则抛出异常。只有当局部命名空间内,使用global 关键字声明了一个变量时,查找顺序则是 a) 的查找顺序。

# def AddMoney():
#     # 想改正代码就取消以下注释:
#     global Money
#   Money=0
# Money = Money + 1 # AddMoney() # print (Money)

作用域 

作用域(包括函数的作用域链):

小范围的可以用大范围的
但是大范围的不能用小范围的
范围从大到小(图)

在小范围内,如果要用一个变量,是当前这个小范围有的,就用自己的
如果在小范围内没有,就用上一级的,上一级没有就用上上一级的,以此类推。
如果都没有,报错

作用域两种
全局作用域 —— 作用在全局 —— 内置和全局名字空间中的名字都属于全局作用域 ——globals()
#globals 永远打印全局的名字
# 对于不可变数据类型 在局部可以是查看全局作用域中的变量
# 但是不能直接修改
# 如果想要修改,需要在程序的一开始添加global声明
# 如果在一个局部(函数)内声明了一个global变量,那么这个变量在局部的所有操作将对全局的变量有效
 
# a = 1
# def func():
#     global a
#     a = 2

# func()
# print(a)
此时结果显示:2 因为函数内声明了变量a=2 若将global a #注释掉,则print(a)=1

 
局部作用域 —— 作用在局部 —— 函数(局部名字空间中的名字属于局部作用域) ——locals()
#locals 输出什么 根据locals所在的位置
#locals 返回一个名字/值对的字典。这个字典的键字是字符串形式的变量名字,字典的值是变量的实际值。
# a = 1
# b = 2
# def func():
#     x = 'aaa'
#     y = 'bbb'
#     print(locals())
#     print(globals())
# 
# func()     
# 此时locals是在局部作用域内,所以显示是{'y': 'bbb', 'x': 'aaa'}



# a = 1
# b = 2
# def func():
#     x = 'aaa'
#     y = 'bbb'
# print(locals())
# print(globals())
#
# func()   
# 此时locals是在全局作用域内,所以显示的是全局的名字

函数的嵌套调用

函数的调用:

# def max(a,b):
#     return a if a>b else b
#
# def the_max(x,y,z):  #函数的嵌套调用
#     c = max(x,y)
#     return max(c,z)
#
# print(the_max(1,2,3))   #打印结果    3   

函数的嵌套:

函数嵌套的定义:

内部函数可以使用外部函数的变量。

a = 1
def outer():
    a = 1
    def inner():
        a = 2
        def inner2():
           # nonlocal a  #声明了一个上面第一层局部变量  a=2
            a = 1   #不可变数据类型的修改
            print('+',a)
        inner2()
        print('##a## : ', a)
    inner()
    print('**a** : ',a)

outer()
print('全局 :',a) 打印显示:     + 1
##a## : 2
**a** : 1
全局 : 1

nonlocal只能用于局部变量,找上层离当前函数最近的局部变量。

声明了nonlocal的内部函数的变量修改会影响到,离当前函数最近一层的局部变量。

对全局无效,对局部也只是对最近一层有影响。

函数名的本质:

  函数名就是一个变量,保存了函数所在的内存地址


# # func()  #函数名就是内存地址
# func2 = func  #函数名可以赋值
# func2():

# # l = [func,func2] #函数名可以作为容器类型的元素 # print(l) # for i in l: # i() # def func(): # print(123) # # def wahaha(f): # f() # return f #函数名可以作为函数的返回值 # # qqxing = wahaha(func) # 函数名可以作为函数的参数 # qqxing()

 

 

闭包:

  内部函数包含对外部作用域而非全局作用域名字的引用,同时外部函数返回内部函数,该内部函数称为闭包函数

x=1
def f1():
x=1000
y=2
def f2():
y=9
print(x)
return y
return f2 #这里返回的是函数f2

f=f1()
print(f) #得到的是一个函数值<function f1.<locals>.f2 at 0x0000000002875840>
f() #此时调用他就可以使得f2内的print生效
print(f())
#打印返回值
print(f.__closure__) #(<cell at 0x0000000002819558: int object at 0x0000000002885410>,)
f.__closure__[0].cell_contents #1000

 闭包都有__closure__属性

__closure__对象会返回闭包应用外围作用域的变量信息。f.__closure__保存外围作用域的变量内存地址,f.__closure__[0].cell_contents存放的是外围作用域的变量的值。

对于那些不是闭包的函数对象来说,__closure__ 属性值为 None。

 

 


 

 

posted @ 2017-12-27 17:47  排骨南  阅读(164)  评论(0编辑  收藏  举报