三元运算:
变量= 条件返回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。