1.三元表达式(三目运算式)
#1 三元表达式(三目运算法)
#格式为: 为真时的结果 if 判定条件 else 为假时的结果
#另外三元表达式只适合较为简洁的条件判定,较为复杂的判定建议不要用这种方式写代码,因为比较让他人难以理解。
a = 10
b = 15
compare = a if a > b else b #谁大返回谁
print(compare)
2.命名空间(namespace)
#2 命名空间(namespace)
#命名空间是名称和对象的印象,也可以将命名空间理解成一个字典,例如定义变量的时候,变量名名就是对应字典的key,而后面的赋值内容就是字典的value,再举例说函数也是一样,函数名就是字典的key,函数体就是字典的value;
#各个命名空间是独立的,没有任何关系的,所以一个命名空间中不能存在重名,但不同的命名空间可以重名并且没有影响。
#在python当中命名空间分为内置空间、全局空间、局部空间三种。
#(1)python解释器拥有自己内置空间,内置的函数在解释器启动时就被加载到内存中,任何模块都可以访问它,它存放着函数和异常。
#(2)每个模块拥有它自已的命名空间,叫做全局命名空间,它记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。
#(3)每个函数都有着自已的命名空间,叫做局部命名空间,它记录了函数的变量,包括函数的参数和局部定义的变量。
3.命名空间查找顺序
#3 命名空间查找顺序
# 假设查找当前命名空间中的“s”变量。
# (1)局部命名空间:首先在局部命名空间中查找,如果没有发现继续去上层全局命名空间查找,如果再没有继续向上层内置命名空间查找,如果再没有python会返回错误。
# (2)全局命名空间:首先在全局命名空间中查找,如果没有发现继续去上层内置命名空间查找,如果再没有python会返回错误。
# (3)内置命名空间:如果在内置命名空间差找不到,直接返回错误。
#1)局部命名空间内调用全局命名空间的变量:
a = 10
def my():
print(a) #可以成功打印出来10
my()
#如果换成这样就不能调用了:
a = 10
def my():
a += 1 #对于不可变类型在局部命名空间中可以查看,但不能直接去修改。
#错误:UnboundLocalError: local variable ‘a‘ referenced before assignment
print(a) #可以成功打印出来10
my()
#在全局命名空间调用内置命名空间的变量:
x = 10
def my(x): # x = 15
print(x) # x =15
my(15)
print(x) # x = 10,全局命名空间只会在当前或上级内置命名空间中查找x,不会去局部命名空间中查找x
4.作用域
#4 作用域
#作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域两种。
#(1)全局作用域:包含内置命名空间和全局命名空间,在整个文件中任意位置可以被引用,并且全局有效。
#(2)局部作用域:局部命名空间,只能在局部范围内有效。
5.globals和locals的区别
# 5 globals和locals的区别
#globals方法
#globals永远打印全局的名字
def a():
print(globals()) #局部命名空间中的输出结果和全局命名空间中的输出结果一样
a()
print(globals())
#locals方法
#输出什么,根据locals所在位置决定。
def func():
a = 10
b = 12
print(locals()) #打印的信息时局部命名空间的变量信息
func()
print(locals()) #打印的信息和globals一样
#global 关键字
#如果在局部命名空间中需要修改全局命名空间的变量值,需要在其之前用global声明即可,其后面的操作将对全局变量有效。
a = 12
def func():
global a #对变量a进行全局声明,之后的操作将对全局的变量有效
a = 25
print(a) # a = 25 对全局变量有效
func()
print(a) # a = 25
6.函数的嵌套和作用域
#6 函数的嵌套和作用域链
#(1)函数的嵌套调用
def my_compare1(a,b): #顺序1
return a if a > b else b #顺序8 #顺序10
def my_compare2(a,b,c): #顺序2
c1 = my_compare1(a,b) #顺序7
return my_compare1(c,c1) #顺序9
a = 10 #顺序3
b = 20 #顺序4
c = 15 #顺序5
print(my_compare2(a,b,c)) #顺序6 #顺序11 打印函数的返回值
#(2)函数的嵌套定义
def f1(): #顺序1
print(‘in f1‘) #顺序3
def f2(): #顺序4
print(‘in f2‘) #顺序6
f2() #顺序5
f1() #顺序2
#(3)函数的作用域链
#one
def f1():
a = 1
def f2():
def f3():
print(a) #打印出的结果是 1 ,因为现在f3属于子局部命名空间,存在父局部命名空间,如果当前子局部域名空间没有,就会向上查找变量a,直至到内置命名空间。
f3()
f2()
f1()
#two
def f1():
a = 1
def f2():
a = 2
f2()
print(‘a in f1 : ‘,a) #此处的变量a,打印出来的是1,因为print和f2函数命名所处f1函数体中,而f2函数体中的a = 2 所处空间是print所在空间的子局部空间,所以print 打印 a的时候不会向下查找。
f1()
#(4)nonlocal关键字
#nonlocal 只能用于局部变量 找上层中离当前函数最近一层的局部变量
#声明了nonlocal的内部函数的变量修改会影响到 离当前函数最近一层的局部变量
a = 10
def f1():
a = 1
def f2():
a = 2
def f3():
nonlocal a #对变量声明nonlocal之后,后面对变量a的操作只会对上一层的局部变量有影响。
a = 2 + 1
f3()
print(‘a in f2:‘,a)
f2()
print(‘a in f1 : ‘,a)
f1()
print(a)
7.函数名的本质
#7 函数名的本质
#函数名本质上就是函数的内存地址
#(1)可以被引用
def func():
print(‘hello word!‘)
fun = func
fun() #fun()和func()调用函数体之后,打印的信息完全一致
func()
#(2)可以被当作容器类的元素
def f1():
print(‘f1‘)
def f2():
print(‘f2‘)
def f3():
print(‘f3‘)
l = [f1,f2,f3]
d = {‘f1‘:f1,‘f2‘:f2,‘f3‘:f3}
#调用
l[0]() #调用f1函数体的内容
d[‘f2‘]() #调用f2函数体的内容
#(3)可以当做函数的参数或返回值
#当参数
def func1():
print(‘abc‘)
def func2(func1):
func1() #调用func1函数
print(‘def‘)
func2(func1) #将func1函数名当做参数传递给func2函数
#当返回值
def func1():
print(‘abc‘)
def func2():
print(‘def‘)
return func1 #将func1函数名当做地址返回
a = func2() #将func1函数的内存地址复制给变量a
a() #调用func1函数
8.闭包
#8 闭包函数
#闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在
# ,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。(看起来相当难以理解)
#对于上面的解释,我总结闭包在嵌套函数的环境中,内部函数调用外部函数的变量,并且外部函数的变量一直存在,下面举个例子看看。
def func():
a = 0
print(‘输出外部函数的变量:‘,a)
def f1():
print(‘内部函数输出变量:‘,a)
return f1
f = func()
f() #第一次调用会打印出来“输出外部函数的变量: 0” 和“内部函数输出变量: 0”
f() #再次调用会打印出来“内部函数输出变量: 0”,包括后面无论几次调用,打印的结果都是这种,不会出现上面的情况,这就是闭包的方式之一
#判断闭包函数的方法__closure__
#输出的__closure__有cell元素 :是闭包函数
def func():
name = ‘eva‘
def inner():
print(name)
print(inner.__closure__) #打印结果:(,) |
return inner
f = func()
f()
#输出的__closure__为None :不是闭包函数
name = ‘egon‘
def func2():
def inner():
print(name)
print(inner.__closure__) #因为外部函数体(局部空间)内不存在变量,所以打印结果:None
return inner
f2 = func2()
f2()