内容一览:
动态参数 *args **kwargs
名称空间(局部,全局,内置)
作用域:全局作用域,局部作用域
加载顺序与取值顺序
内置函数:globals() locals()
关键字: global nonlocal
函数的嵌套(高阶函数)
函数的初识:
封装一个功能
def 函数名():
函数体
函数的返回值:return
1.结束函数
2.返回给执行者值
return ---> 返回 None
return单个值 ---> 返回单个值
return多个值 ---> 返回一个元组
函数的参数:
实参:
1.位置参数——必须与形参角度的位置从左到右一一对应
2.关键字参数——必须一一对应,可以不按顺序
3.混合参数——位置参数必须在关键字参数前面
形参:
1.位置参数——必须与实参角度的位置从左到右一一对应
2.默认参数——必须一一对应
3.动态参数——*args, **kwargs
1 # 动态参数 *args **kwargs 2 3 def func(*args, **kwargs): # 这句表示在函数的定义时,*表示函数的聚合 4 print(args) 5 print(kwargs) 6 func(1, 2, 3, 4, 5, "alex", name="taibai", sex="男") 7 8 # (1, 2, 3, 4, 5, ‘alex‘) 9 # {‘name‘: ‘taibai‘, ‘sex‘: ‘男‘}
1 # *的魔性用法 2 3 # 写一个函数,可以传入多个列表,把列表里的所有元素一个一个添加到args里面 4 5 def func(*args, **kwargs): 6 print(args) 7 set = func(*[1, 2, 3], *(1, 2, 3), *"askj") # 函数调用时,*代表打散 8 print(set) 9 10 # (1, 2, 3, 1, 2, 3, ‘a‘, ‘s‘, ‘k‘, ‘j‘) 11 # None 12 13 14 def func(**kwargs): 15 print(kwargs) 16 func(**{"name": "alex"}, **{"age": 16}) 17 18 # {‘name‘: ‘alex‘, ‘age‘: 16} 19 20 21 def func(*args, **kwargs): 22 print(args) 23 print(kwargs) 24 func(*[1, 2, 3], *"adj", **{"name": "alex"}, **{"age": 16}) 25 26 # (1, 2, 3, ‘a‘, ‘d‘, ‘j‘) 27 # {‘name‘: ‘alex‘, ‘age‘: 16} 28 29 # 总结 30 # 在函数定义时,* **代表聚合 31 # 在函数调用时,* **代表打散
1 # 特殊用法 2 a, b, *args = [i for i in range(20)] 3 print(a, b, args) 4 # 0 1 [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] 5 6 # 小 bug 7 8 def func(*args, **kwargs): 9 print(args) 10 print(kwargs) 11 func(*[1, 2, 3], *"adj", **{1: "alex"}, **{"age": 16}) 12 13 # 这里如果字典里的key是数字就不行,必须是字符串 14 # 比如这样就可以 15 16 def func(*args, **kwargs): 17 print(args) 18 print(kwargs) 19 20 func(*[1, 2, 3], *"adj", **{"name": "alex"}, **{"age": 16}) 21 22 # (1, 2, 3, ‘a‘, ‘d‘, ‘j‘) 23 # {‘name‘: ‘alex‘, ‘age‘: 16}
1 # 形参的顺序问题 2 # 下面这些的顺序怎么排? 3 # a, b, c, sex="男", *args, **kwargs 4 5 # 位置参数一定要在默认参数的前面 6 def func(a, b, sex="男"): 7 print(a) 8 print(b) 9 print(sex) 10 func(1, 2, sex="女") # 这里也可以把 sex= 去掉 11 12 # 1 13 # 2 14 # 女 15 16 17 def func(a, b, *args, sex="男"): 18 print(a) 19 print(b) 20 print(args) 21 print(sex) 22 func(1, 2, "女", "非男") 23 24 # 1 25 # 2 26 # (‘女‘, ‘非男‘) 27 # 男 28 29 30 def func(a, b, *args, sex="男"): 31 print(a) 32 print(b) 33 print(args) 34 print(sex) 35 func(1, 2, "女", "非男", sex="女") 36 37 # 1 38 # 2 39 # (‘女‘, ‘非男‘) # 都传递给了args 40 # 女 41 42 43 def func(a, b, *args, sex="男", **kwargs): 44 print(a) 45 print(b) 46 print(args) 47 print(sex) 48 print(kwargs) 49 func(1, 2, "女", "非男", sex="女", name="alex") 50 51 # 1 52 # 2 53 # (‘女‘, ‘非男‘) 54 # 女 55 # {‘name‘: ‘alex‘} 56 57 58 # 总结(很重要): 59 # 形参的排序 ---> 位置参数 > *args > 默认参数 > **kwargs
程序开始运行时是逐行解释,从上往下运行
遇到了初始化对象命令时,在内存中存放一个变量与值的对应关系的空间,称为全局名称空间
def func():
sex = "男"
func()
程序走到这个函数时,看到函数的定义,会把函数名与函数体的对应关系在内存中存放一个命名空间,里面没有任何东西
遇到函数调用时,会在内存中再开辟一个临时的名称空间,存放的是函数体里面的变量与值(sex="男"),该临时名称空间会随着函数的结束而消失
因此在 func() 下一行加 print(sex)时没有结果
因为函数已经结束,这个临时名称空间(局部名称空间)已经消失了
全局名称空间:存放的是py文件中变量与值的对应关系
局部名称空间:临时存放的是函数体里面的变量与值的对应关系
内置名称空间:内置函数,关键字等等,比如 print(), input()
作用域,分为全局作用域与局部作用域
全局作用域:全局名称空间,内置名称空间
局部作用域:局部名称空间
加载顺序——加载到内存的顺序
内置名称空间 ---> 全局名称空间 ---> 局部名称空间
解释器加载到内存中才能写代码,这个时候内置函数已经一起加进内存去了,所以内置名称空间是最先加载的
接下来运行程序,肯定是先加载全局名称空间,遇到函数时才加载局部名称空间
1 # 取值顺序(就近原则) 2 3 def func(): 4 name = "flash" 5 print(name) 6 func() # flash 7 8 name = "alex" 9 def func(): 10 name = "flash" 11 print(name) 12 func() # flash 13 # 这里 print(name)是先打印里面的name 对应的变量——即所谓的就近原则 14 15 name = "alex" 16 def func(): 17 # name = "flash" 18 print(name) 19 func() # alex 20 # 这时局部名称空间里已经没了name这个变量对应的值,所以它就在外面找 21 22 input = "alex" 23 def func(): 24 print(input) 25 func() # alex 26 27 # 因此取值顺序是 28 # 局部名称空间 --> 全局名称空间 --> 内置名称空间
1 # LEGB 原则,也是就近原则 2 3 name = "三包" 4 def func(): 5 name = "alex" 6 # print(name) 7 def inner(): 8 name= "barry" 9 print(name) 10 inner() 11 # print(name) 12 func() 13 14 # 因此这个程序运行结果是 barry 15 # 如果把 print(name) 放在 "alex" 下面,结果是 alex 16 # 如果把 print(name) 放在 func() 上面, 则打印 三包
1 # 内置函数: globals() locals() 2 3 name = "alex" 4 age = 16 5 6 def func(): 7 name = "barry" 8 age = 18 9 10 print(globals()) 11 print(locals()) 12 13 # {‘__name__‘: ‘__main__‘,..., ‘name‘: ‘alex‘, ‘age‘: 16} 14 15 # {‘__name__‘: ‘__main__‘,..., ‘name‘: ‘alex‘, ‘age‘: 16} 16 17 # globals() 打印结果是一个字典,里面内容很多,包含全局作用域的所有内容 18 # locals() 返回的是当前作用域的内容 19 20 name = "alex" 21 age = 16 22 23 def func(): 24 name = "barry" 25 age = 18 26 print(globals()) 27 print(locals()) 28 func() 29 30 # {‘__name__‘: ‘__main__‘,..., ‘name‘: ‘alex‘, ‘age‘: 16} 31 32 # {‘age‘: 18, ‘name‘: ‘barry‘} 33 # 这里发现 locals() 的结果出来了,因为在当前作用域有内容 34 35 name = "alex" 36 age = 16 37 38 def func(): 39 name = "barry" 40 age = 18 41 def inner(): 42 print(globals()) 43 print(locals()) 44 inner() 45 func() 46 47 # {‘__name__‘: ‘__main__‘,..., ‘name‘: ‘alex‘, ‘age‘: 16} 48 49 # {} 50 51 # 注意刚才说的 locals()返回的是当前作用域的内容,而这里的“当前”什么也没有,因此打印空字典 52 53 # 无论是加载顺序还是取值顺序都是单向不可逆的
1 # 高阶函数 2 # 记住一点:代码是从上往下执行的!!! 3 # 注意观察下面几个函数的对比 4 5 def func1(): 6 print(111) 7 8 def func2(): 9 print(222) 10 func1() 11 12 def func3(): 13 print(333) 14 func2() 15 print(555) 16 func3() 17 print(666) 18 19 # 555 20 # 333 21 # 222 22 # 111 23 # 666 24 25 # 先是执行 print(555) 26 # 然后执行函数 27 # 先执行 func3 28 # 执行完后要等 func3 里面的 func2执行 29 # func2 执行后要等里面的 func1 执行 30 # 最后才执行 print(666) 31 32 def func1(): 33 print(1) 34 def inner(): 35 print(2) 36 def inner2(): 37 print(3) 38 print(4) 39 inner() 40 print(5) 41 func1() 42 43 # 1 44 # 4 45 # 2 46 # 5 47 48 # 注意顺序 49 # 先执行 print(1) 50 # 再执行 print(4) 51 # 再执行 innner(),这里只执行 print(2),不执行 inner2() 52 # 最后执行 print(5)
1 # global nonlocal 2 # global 可以在局部声明一个变量 3 4 def func(): 5 name = "alex" 6 func() 7 print(name) 8 9 # 报错,找不到 name,因为 name 在局部名称空间 10 11 def func(): 12 global name 13 name = "alex" 14 func() 15 print(name) # alex 16 17 # 这里 global name 相当于表示不仅在局部有这个变量对应的值,全局也有(同步) 18 19 age = 46 20 def func(): 21 global name 22 name = "alex" 23 name = "barry" 24 func() 25 print(name) # barry 26 27 # 在局部改变了这个变量对应的值的话,全局也会同步改变 28 # 这里注意函数执行结束后,全局的变量指向的值在内存中还存在 29 30 age = 46 31 name = "xxx" 32 def func(): 33 global name 34 name = "alex" 35 name = "barry" 36 func() 37 print(name) # barry 38 39 # 这里相当于局部可以操控全局 40 41 age = 46 42 name = "xxx" 43 def func(): 44 global name 45 name = "alex" 46 name = "barry" 47 func() 48 name = "aaa" 49 print(name) 50 51 count = 1 52 def func(): 53 count += 1 54 func() 55 56 # 局部作用域不能对全局作用域的变量进行修改,只能引用 57 58 count = 1 59 def func(): 60 global count 61 count += 1 62 func() 63 print(count) 64 # 说明可以通过设置global就可以修改 65 66 # global用法总结: 67 # 可以局部作用域声明一个全局变量 68 # 局部作用域不能对全局作用域的变量进行修改,只能引用,但可以通过设置global修改
1 # nonlocal: 只在python3x中存中 2 # 子级对父级的操控 3 4 # 不能操控全局变量 5 name = "alex" 6 def func(): 7 nonlocal name 8 print(name) 9 func() 10 11 # 内存函数可以引用外出函数的变量 12 def wrapper(): 13 name = "alex" 14 def inner(): 15 print(name) 16 inner() 17 wrapper() 18 19 # 内层函数只能引用外层函数的变量,不能改变 20 def wrapper(): 21 name = "alex" 22 def inner(): 23 name += "b" 24 inner() 25 wrapper() 26 # 报错 27 28 # 非要修改,只能用nonlocal 29 def wrapper(): 30 name = "alex" 31 def inner(): 32 nonlocal name 33 name += "b" 34 print(name) 35 inner() 36 wrapper() 37 38 39 def wrapper(): 40 name = "alex" 41 def inner(): 42 nonlocal name 43 name += "b" 44 print(name) 45 print("1", name) 46 inner() 47 print("2", name) 48 wrapper() 49 50 # 先执行 print("1", name) 51 # 再执行 inner(),name变量指向的值已经变为 alexb 52 # 最后执行 print("2", name)时,因为前面已经执行 inner(),因此从第二步开始,往下所有的name变量指向的值都变成了 alexb
原文:https://www.cnblogs.com/shawnhuang/p/10198125.html