内容一览:
动态参数 *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