第七章 函数
函数
代码得是一种组织形式
函数是对功能的封装—一个函数一般完成一项特定的功能
函数的使用:
- 函数需要先定义
- 使用函数俗称调用
语法:
def 函数名(形参列表):
函数体(代码块. return)
调用:
函数名(实参列表)
# 定义一个函数 # 只是定义的话不会执行 # 1 . def是关键字 # 2 . 遵循命名规则,约定俗成,不使用大驼峰 # 3 . 括号和冒号不能省,括号内可以有参数 def func(): print("我是一个函数") print("我要完成一定的功能") print("我结束了")
"""多行注释"""
def func(a, b):
"""
这个函数的功能是什么
:param a: 形参a的意义
:param b: 形参b的意义
:return: 返回的是什么东西
"""
print(func.__doc__) # 读取函数文档
1. 返回值
return: 在函数执行的时候.如果遇到return.直接返回
1. 如果函数什么都不写,不写return,没有返回值.得到的是None
2. 在函数中写return值,返回一个值
3. 在函数中间或者末尾写return,返回的是None
4. 在函数中可以返回多个返回值.return值1, 值2, 值3, ……接受的是元组
1 # return语句的基本使用 2 # 函数打完招呼后返回一句话 3 def hello(person): 4 print("{0}你肿么了?".format(person)) 5 print("Sir,你不理我了吗?") 6 7 return"我已近跟{0}打招呼了".format(person) 8 p = "小仙女" 9 rst = hello(p) 10 11 print(rst)
1 # return案例2 2 # 函数打完招呼后返回一句话 3 def hello(person): 4 print("{0}你肿么了?".format(person)) 5 return("哈哈{0},我先走啦".format(person)) 6 print("Sir,你不理我了吗?") 7 8 return"我已近跟{0}打招呼了".format(person) 9 p = "小仙女" 10 rst = hello(p) 11 12 print(rst)
2. 参数
函数执行的时候给函数传递信息
* 形参:函数声明的位置的变量,在函数定义的时候用到的参数,没有具体的值,只是一个占位发号
* 实参: 函数调用的时候给的具体的值
传参:把实参交给形参的过程
2.1 实参:
1. 位置参数,按照形参的参数位置给形参传值
2. 关键字参数,按照形参的名字给形参传值
3. 混合参数。即用位置参数,也用关键字参数
2.2 形参:
1. 位置参数
2. 默认值参数,先位置后默认值
3. 动态参数
1 # 参数的定义和使用 2 3 def hello(person): 4 print("{0}你肿么了?".format(person)) 5 print("Sir,你不理我了吗?") 6 7 p = "小仙女" 8 hello(p)
3. 函数的动态参数
*argue位置参数动态传递
在这里表示接收位置参数的动态传参,接收到的是元组
*args表示任何多个位置参数,他是一个tuple;
**kwargue关键字参数的动态传递
在这里表示接受关键字参数的动态传参,接受到的是字典
**kwargue 表示任何多个关键字参数,他是一个dict。并且同时使用*argue和**kwargue时,必须*args参数要在**kwargs前。
**kwarg有一个很漂亮的用法:
1 def kw_dict(**kwargs): 2 return kwargs 3 print kw_dict(a = 1, b = 2, c = 3) 4 ==> {'a':1, 'b':2, 'c'::3}
其实python中就带了dict类,使用dict(a=1, b=2, c=3)即可创建一个字典
顺序: 位置参数 >> *argue >> 默认值参数 >> **kwargue
1 # 可以接受所有的参数的函数 2 def func(*argue, **kwargue): 3 pass
形参的位置(*,**):聚合
实参的位置(*,**):打散 在实参位置上给一个序列、列表、可迭代对象前面加上*表示把这个序列按顺序打散,如果是一个字典则需要两个*
4. 命名空间
在python解释器开始执⾏之后, 就会在内存中开辟⼀个空间, 每当遇到⼀个变量的时候, 就 把变量名和值之间的关系记录下来, 但是当遇到函数定义的时候, 解释器只是把函数名读入内 存, 表⽰这个函数存在了, ⾄于函数内部的变量和逻辑, 解释器是不关⼼的. 也就是说⼀开始 的时候函数只是加载进来, 仅此⽽已, 只有当函数被调⽤和访问的时候, 解释器才会根据函数 内部声明的变量来进⾏开辟变量的内部空间. 随着函数执⾏完毕, 这些函数内部变量占⽤的空 间也会随着函数执⾏完毕⽽被清空。
命名空间:存放名字和值关系的空间。
分类:
1. 内置名称空间 — 存放 python解释器为我们提供的名字,list、tuple、str等这些都是内置命名空间
2. 全局名称空间 — 我们直接在py文件中,函数外声明的变量都属于全局命名空间,包括最外层的函数命名也属于全局名称空间
3. 局部名称空间 — 在函数中声明的变量会放在局部命名空间
加载顺序:
- 内置命名空间
- 全局命名空间
- 局部命名空间(函数被执行的时候)
取值顺序:
- 局部命名空间
- 全局命名空间
- 内置命名空间
作用域:
作用域就是作用范围,按照生效的范围来看分为全局作用域和局部作用域
1.全局作用域:内置+全局 在整个文件的任何位置都可以使用(遵循由上到下逐行执行)
2. 局部作用域: 局部(当函数被调用的时候) 在函数内部可以使用
globals():查看全局中的内容
loca0ls():查看当前局部作用域中的变量和函数信息
1 a = 10 2 def func(): 3 a = 40 4 b = 20 5 def abc(): 6 print("这是函数的嵌套") 7 print(a, b) # 这里使用的是局部作用域 8 print(globals()) # 打印全局作用域中的内容 9 print(locals()) # 打印局部作用域中的内容
5. 函数嵌套
函数可以互相的嵌套:
1 def hano(n,a,b,c): 2 ''' 3 汉诺塔的递归实现 4 n:代表几个盘子 5 a:代表第一个塔,开始的塔 6 b:代表第二个塔,中间过度的塔 7 c:代表第三个塔,目标塔 8 ''' 9 if n==1: 10 print(a, "-->", b) 11 if n==2: 12 print(a, "-->", b) 13 print(a, "-->", c) 14 print(b, "-->", c) 15 return None 16 #把n-1个盘子,从a塔借助于c塔,挪到b塔上去 17 hano(n-1,a,c,b) 18 print(a,"-->",c) 19 #把n-1个盘子,从b塔,借助于a塔,挪到c塔上去 20 hano(n-1,b,a,c) 21 22 a="A" 23 b="B" 24 c="C" 25 n=1 26 hano(n,a,b,c) 27 n=2 28 hano(n,a,b,c) 29 n=3 30 hano(n,a,b,c) 31 n=5 32 hano(n,a,b,c)
6. global和nonlocal
global:表示不再使用局部作用域中的内容,改用全局作用域中的变量
a = 100 # 全局变量 a
def func():
global a # globa是允许函数中访问目标全局变量
a = 20 #此时才能对全局变量进行更改操作
print(a) # 如果不用globa 只允许函数内对全局变量进行不更改值的操作 比如print
func()
print(a) # 全局变量在函数体内部被更改 所以此处输出的是28
nonlocal:表示在局部作用域中,调用父级命名空间中的变量(在局部寻找外层函数中离他最近的那个变量)
1 a = 10 2 def func(): 3 a = 20 # 4 但是这层的a值不会改变 4 def func2(): 5 a = 30 # 3 这个被更改了 6 def func3(): 7 nonlocal a # 1 引进最近的变量a 但是不能是全局作用域中的变量 会报错 8 a = 40 # 2 将父辈函数的a值更改 9 print(a) # 输出40 10 func3() 11 print(a) # 输出40 12 func2() 13 print(a) # 输出20 14 func() 15 print(a) # 输出全局变量10