Python 语言-第五章函数与变量
第五章函数与变量
5.1 函数定义与调用
5.1.1 函数定义
-
函数:执行特定任务和以完成特定功能的一段代码
-
用途:
- 复用代码
- 隐藏实现细节
- 提高可维护性
- 提高可读性便于调试
-
语法格式:
def 函数名(形式参数): 函数体 [return 表达式]
形式参数:仅仅启占位符的作用,可以与后面的实参相同或不同
return 函数使系统有选择性的返回一个值给调用代码
-
例如:
def calc(a,b): c = a + b return c
-
5.1.2 函数调用
-
调用函数时,直接在语法中输入函数名并在后面的圆括号内传入实际参数(简称实参),多个参数之间用逗号隔开。
-
语法格式:
函数名(实际参数列表)
此时提供的实际参数应当与定义该函数时指定的形式参数按顺序相对应,而且参数的数据类型要保持兼容。
-
例如:这个是上面定义函数例子的调用
a = calc(10,20)
-
实现逻辑:
-
5.2 形式参数的定义
-
函数定义默认值形参
-
函数定义时,给形参设置默认值,只有与默认值不符时才需要传递实参
-
例如:
def fun(a,b = 10): print(a,b) #函数调用 fun(100) fun(20,30)
100 10 20 30
- 第一次调用 fun 函数时只传一个参数,b 采用默认值
- 第二次调用 fun 函数 30 将默认值 100 替换
-
带有默认值的形参只能放在最右边
-
-
个数可变的位置形参
-
定义函数时,往往无法事先确定传递的位置实参个数,就可以使用可变的位置参数
-
使用
*
定义个数可变的位置形参 -
结果为一个元组,所以也可以叫元组类型变长参数(爱咋咋叫)
-
例如:
def fun(*args): print(args) fun(10) fun(10,20,30)
(10,) (10, 20, 30)
-
个数可变的位置参数只能放在形参最右边
-
-
个数可变的关键字形参
-
定义函数时,定义函数时,无法事先确定传递的位置实参个数,不仅可以使用元组类型变长参数,还可以使用个数可变的关键字形参
-
使用
**
定义个数可变的关键字形参 -
结果为一个字典,所以也可以叫字典类型变长参数
-
例如:
def fun(**args): print(args) fun(a = 10) fun(a =10,b = 20,c = 30)
{'a': 10} {'a': 10, 'b': 20, 'c': 30}
-
个数可变的位置参数只能放在形参最右边
-
当默认值形参、元组类型变长参数、字典类型变长参数在一起怎么排序?
-
规则:字典类型变长在最右边,其他都行
def fun(*args1,a = 10,**args2,): pass def fun(a = 10,*args1,**args2,): pass
-
-
-
5.3 函数参数传递
5.3.1 函数参数的传递方式
-
通常函数参数传递方式分为两种:值传递和引用传递
- 值传递:结果不变
- 引用传递:结果可变
-
在 python 中两种函数传递都可以:可变的为引用传递,不可变为值传递
- 在函数调用时,进行参数传递,如果是可变对象,在函数体中修改会影响到实参的值;如果是不可变对象,在函数体种修改不会影响到实参的值
5.3.2 函数参数的类型
-
位置参数
- 根据形参对应位置,按照从左到右的顺序依次传递相应实参
- 要求实参个数=形参个数,如果实参个数不等于形参个数,会出现 TypeError 异常
- 是参数传递时的默认参数类型
-
关键字参数
-
根据形参名进行传递关键字参数
-
例如:
def c(a, b): print(a, b) c(b=10, a=20)
-
-
5.3.3 函数调用的参数传递内存分析图
-
示例:
-
为什么 n1 进入 run 函数后,仍然是输出原来的 11,而 n2 输出结果添加了一个元素 10
- 从内存分析图可以得出结论
-
内存分析图
5.4 函数调用
-
位置调用:按照形参的位置,依次调用
-
普通的位置传参:假设已经定义有三个形参的 fun 函数
fun(1,2,3)
-
通过列表实现位置传参:假设已经定义有三个形参的 fun 函数
lst = [1,2,3] fun(*lst)
- 需要使用:
*
符号
- 需要使用:
-
-
关键字调用:通过关键字传参的方式进行调用
-
普通的关键字传参:假设已经定义有三个形参的 fun 函数
fun(a=1,b=2,c=3)
-
通过字典进行关键字传参:假设已经定义有三个形参的 fun 函数
dic = ['a':1,'b':2,'c':3] fun(**dic)
- 需要使用:
**
符号 - 其中字典中的键转化为实参符号,值转化为实参的值
- 需要使用:
-
-
位于 * 后面的形参,只能采用关键字传参
def fun(a,b,*,c,d): print(a,b,c,d) fun(10,20,c = 30,d = 40)
5.5 函数的返回值
- 如果函数没有返回值【函数执行完毕之后,不需要给调用处提供数据】,return 可以不写
- 如果有函数返回值
- 返回一个值时,直接返回对应数据类型
- 返回多个值(大于 1 个值)时,返回结构为元组
5.6 变量的作用域
- 变量的作用域:程序中能够对变量进行存取操作的范围
- 根据变量的有效范围可以分为:局部变量和全局变量
5.6.1 局部变量
- 局部变量
- 在函数内定义并使用的变量,只在函数内部有效
- 局部变量转为全局变量
- 使用 global 声明,就可以将局部变量转为全局变量
5.6.2 全局变量
-
全局变量
- 在模块级别上,在所有函数外部定义的变量,可作用于函数内外
-
Python程序中引用变量的优先顺序(缺省条件下)
- 当前作用域局部变量 > 外层作用域变量 > 当前模块的全局变量 > Python内置函数
5.6.3 闭包
-
如果在函数内部又定义了另一个函数,在内层函数中对外层函数中定义的局部变量进行存取操作,并且外层函数返回对内层的引用,则这个内层函数称为闭包
-
例如:
def outer_fun(age): #定义外层函数 msg="学生信息" def inner_fun(name,gender): #定义内层函数 print("{0};{1};{2};{3}岁".format(msg,name,gender,age)) return inner_func #返回对内层函数的引用 stu1=outer_func(19) stu1("张志明","男") print("-"*50) stu2=outer_func(18) stu2("李春娇","女")
- inner_fun 函数 是嵌入outer_fun 函数的内层函数,inner_fun 引用了外层作用域中的 msg、age,同时 outer_fun 函数返回了 inner_fun 函数,所以 inner_fun 这个内部函数就形成了一个闭包。
5.7 两类特殊的函数
5.7.1 匿名函数
-
匿名函数
- 匿名的意思是不再使用 def 语句这样标准的形式定义一个函数。
-
语法格式:
lambda [arg1 [,arg2,.....argn]]:expression
- lambda 是单一的表达式,而不是语句块,仅仅能在 lambda 表达式中封装有限的逻辑
- lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
- lambda 函数看起来只能写一行,不等同于 C 或 C++ 的内联函数
-
普通使用例如:
sum = lambda arg1, arg2: arg1 + arg2; print ("相加后的值为 : ", sum( 10, 20 ))
- 由于 lambda 返回的是函数对象(构建的是一个函数对象),所以需要定义一个变量去接收
- 匿名函数还有其他使用方法,就不再介绍了
-
优点
- 让代码更加精简。
- 不需要考虑命名的问题
- 代码更容易理解
5.7.2 递归函数
-
递归函数:
- 在一个函数的函数体内调用了该函数本身,这个函数就被称为递归函数
-
组成成分:
- 递归调用和终止条件
-
调用过程:(先调用后运算,计算一个,销毁一个)
- 每递归调用一次函数,都会在栈内存分配一个栈帧
- 每执行完一次函数,就释放相应的空间
-
优缺点:
- 优点:思路代码简单
- 缺点:占用内存多,效率低下
-
例如:计算 6 的阶乘
def fac(n): if n == 1: return 1 else : return n*fac(n-1) print(fac(6))