文章目录
-
- 1、函数声明
- 2、函数调用
- 3、函数参数
-
- 3.1、形参和实参
- 3.2、位置参数
- 3.3、默认参数
- 3.4、关键字参数
- 3.5、不定长参数
- 4、函数返回值
-
- 4.1、基本使用
- 4.2、默认返回值
- 4.3、返回多个值
- 5、变量作用域
-
-
- 5.1 变量只能在所在的函数内部生效
- 5.2 如果函数内部尝试访问的变量在局部不存在,就会尝试去全局作用域中查找
- 5.3 如果是想在函数内部,修改全局变量 的值,需要使用global关键字声明
-
- 6、函数嵌套
- 7、函数递归
-
- 7.1、递归计算(5的阶乘5!)
- 7.2、递归的优缺点
1、函数声明
声明一个函数,也就是创建一个函数,可以理解为将一段可以重复使用的代码通过关键字def包裹起来。具体的语法格式如下:
def 函数名(参数列表):
'''
# 函数文档,实现特定功能的多行代码
params:
return:
'''
[return [返回值]]
其中,用 [] 括起来的为可选择部分,即可以使用,也可以省略。此格式中,各部分参数的含义如下:
- 函数名:一个符合 Python 语法的标识符,最好见名知意,多个单词可以使用_表示,比如cal_sum
- 形参列表:设置该函数可以接收多少个参数,多个参数之间用逗号( , )分隔。
- [return [返回值] ]:整体作为函数的可选参参数,用于设置该函数的返回值。
- python的函数体是通过冒号+缩进声明的
def foo():
print("foo函数")
2、函数调用
函数的声明并没有执行函数中的代码块,想要执行函数体,需要进行函数调用,一个函数可以调用多次。
函数调用语法:
# 函数名() # 不考虑参数和返回值的调用
def foo():# 函数声明,函数名foo
print("foo函数")
foo()# 函数调用
debug模式运行:
# 函数的声明
def bar():
print("bar1")
print("bar2")
print("bar3")
# 函数调用
bar()
3、函数参数
3.1、形参和实参
# 案例1
def cal_sum(temp): # temp就是引入的函数形式参数
ret = 0
for i in range(1,temp+1):
ret+=i
print(ret)
cal_sum(100) # 每次调用可以根据需要传入需要的值,这个具体的值成为实际参数简称实参。
cal_sum(101)
# 案例2
def add():
x = 10
y = 20
print(x+y)
def add(x, y): # 声明的参数称之为形式参数,简称形参
print(x + y)
# 调用add函数 # 将调用过程中传入的值称之为实际参数,简称实参
add(5, 6) # 将5赋值给x,将6赋值给了y ,函数体将x+y,即5+6计算出来,打印
# 调用add函数
add(10, 5) # 将10赋值给x,将6赋值给了5 ,函数体将x+y,即10+5计算出来,打印
在函数的定义阶段 括号内写的变量名,叫做该函数的形式参数,简称形参。在函数的调用阶段,括号内实际传入的值,叫做实际参数,简称实参。该例中,temp就是的函数形式参数,而每次调用根据需要传入的值,比如100,101都是实参。
形参就相当于变量名,而实参就相当于变量的值,函数调用传参的过程 就是给形参变量名赋值的过程。
函数参数只有在函数调用阶段有效,函数运行结束,参数作为垃圾释放。
3.2、位置参数
位置参数,有时也称必备参数,指的是必须按照正确的顺序将实际参数传到函数中,换句话说,调用函数时传入实际参数的数量和位置都必须和定义函数时保持一致。
# 例1
def add(x,y): # x,y是形参,用来接收实参
print(x+y)
add(2,3) # 2,3 是实际参数,分别传递给形参x,y
# 例2
def add(x,y,z):
print(x+y)
add(2,3) # 报错:缺少一个实际参数传递给z
# 例3
def add(x,y):
print(x+y)
add(2,3,4) # 报错:缺少一个形式参数接收给z
3.3、默认参数
Python 允许为参数设置默认值,即在定义函数时,直接给形式参数指定一个默认值。这样的话,即便调用函数时没有给拥有默认值的形参传递参数,该参数可以直接使用定义函数时设置的默认值。
def print_stu_info(name,age,gender="male"):
print("学员姓名:",name)
print("学员年龄:",age)
print("学员性别:",gender)
print_stu_info("张三",23)
当定义一个有默认值参数的函数时,有默认值的参数必须位于所有没默认值参数的后面,否则报错!
3.4、关键字参数
关键字参数可以避免牢记参数位置的麻烦,令函数的调用和参数传递更加灵活方便。关键字参数是指使用形式参数的名字来确定输入的参数值。通过此方式指定函数实参时,不再需要与形参的位置完全一致,只要将参数名写正确即可。
def print_stu_info(name,age,height,weight,job):
print("学员姓名:",name)
print("学员年龄:",age)
print("学员身高:",height)
print("学员体重:",weight)
print("学员工作:",job)
print_stu_info("张三",23,"180cm","80kg","销售")
print_stu_info(name="张三",height="180cm",weight="90kg",job="销售",age=23)
print_stu_info("张三",height="180cm",weight="90kg",job="销售",age=23)
使用位置参数和关键字参数混合传参的方式。但需要注意,混合传参时关键字参数必须位于所有的位置参数之后。
3.5、不定长参数
在函数定义中使用*args和**kwargs传递可变长参数。*args用作传递非命名键值可变长参数列表(位置参数);**kwargs用作传递键值可变长参数列表。*args 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。**kwargs的参数会以字典的形式导入。
# *args
def add(*args):
print(args)
print(type(args))
ret = 0
for i in args:
ret += i
print(ret)
add(12,23,45)# 参数以元祖的形式导入
# **kwargs
def print_stu_info(**kwargs,):
print(kwargs)
print_stu_info(name="张三",height=190)# 参数以字典的形式导入
同时使用*args和**kwargs:
def print_stu_info(name, age=18, *args, **kwargs):
print(name, age)
print(args)
print(kwargs)
print_stu_info("yuan", 20, "China", "Beijing", height="188cm", weight="60kg")
注意点:
1、参数arg、*args、**kwargs三个参数的位置必须是一定的。必须是(arg,*args,**kwargs)这个顺序,否则程序会报错。
2、不定长参数的长度可以为零。
3、args 和 kwargs其实只是编程人员约定的变量名字,args 是 arguments 的缩写,表示位置参数;kwargs 是 keyword arguments 的缩写,表示关键字参数。
4、函数返回值
到目前为止,我们创建的函数都只是对传入的数据进行了处理,处理完了就结束。但实际上,在更多场景中,我们还需函数将处理的结果反馈回来。通过关键字return语句可以返回任意类型的数值。
4.1、基本使用
def add(x,y):
return x+y # return是函数的终止语句
ret = add(2,3)# 变量ret接收add函数的返回值
print(ret)
4.2、默认返回值
在 Python 中,有一个特殊的常量 None(N 必须大写)。和 False 不同,它不表示 0,也不表示空字符串,而表示没有值,也就是空值。None 是 NoneType数据类型的唯一值(其他编程语言可能称这个值为 null、nil 或 undefined),也就是说,我们不能再创建其它 NoneType类型的变量,但是可以将 None 赋值给任何变量。
Python一个函数中如果没有return语句或者return后没有具体值,都默认返回None,比如print()函数就没有返回。
4.3、返回多个值
return也可以返回多个值,python其实会将多个值放在一个元组中元组返回。
def login(user,pwd):
flag = False
if user == 'yuan' and pwd == 123:
flag = True
return flag,user# 执行到return语句,函数就会立即执行结束,回到调用位置
# ret = login("yuan",123)
flag,user = login("yuan",123)
if flag:
print("{}登陆成功!".format(user))
else:
print("用户名或者密码错误!")
5、变量作用域
5.1 变量只能在所在的函数内部生效
在函数getPoint内部定义的x、y只是在函数内部生效,一旦出了函数的范围,这两个变量就不再生效。
def getPoint():
x = 10
y = 20
return x, y
getPoint()
print(x, y)# 报错:NameError:name 'x' is not define
注意: 在函数内部的变量,也称为“局部变量”; 不在任何函数内部的变量,也称为“全局变量”。
5.2 如果函数内部尝试访问的变量在局部不存在,就会尝试去全局作用域中查找
x = 20
def test():
print(f'x = {x}')
test()
# 打印出:x= 20
5.3 如果是想在函数内部,修改全局变量 的值,需要使用global关键字声明
x = 20
def test():
global x
x = 10
print(f'函数内部 x = {x}')# 函数内部 x = 10
test()
print(f'函数外部 x = {x}')# 函数外部 x = 10
6、函数嵌套
函数内部还可以调用其他的函数,这个动作称为 “嵌套调用”。
def foo():
def bar():
print("bar功能")
print("foo功能")
foo()
一个函数里面可以嵌套调用任意多个函数
def a():
print("函数 a")
def b():
print("函数 b")
a()
def c():
print("函数 c")
b()
def d():
print("函数 d")
c()
d()

7、函数递归
递归是嵌套调用中的一种特殊情况:即一个函数嵌套调用自己。
7.1、递归计算(5的阶乘5!)
def factor(n):
if n == 1:
return 1
return n * factor(n – 1)
result = factor(5)
print(result)
上述代码中,就属于典型的递归操作。在 factor 函数内部,又调用了 factor 自身。
注意:递归代码务必要保证——
(1)存在递归结束条件:比如if n == 1就是结束条件,当n为1的时候,递归就结束了; (2)每次递归的时候,要保证函数的实参是逐渐逼近结束条件的。
如果上述条件不能满足,就会出现“无限递归”,这是一种典型的代码错误。
7.2、递归的优缺点
-
递归的优点 (1)递归类似于“数学归纳法”,明确初始条件,和递推公式,就可以解决一系列的问题; (2)递归代码往往代码量非常少。
-
递归的缺点 (1)递归代码往往难以理解,很容易超出掌控范围; (2)递归代码容易出现栈溢出的情况; (3)递归代码往往可以转换成等价的循环代码,并且通常来说循环版本的代码执行效率要略高于递归版本。
注意:递归代码务必要保证——
(1)存在递归结束条件:比如if n == 1就是结束条件,当n为1的时候,递归就结束了; (2)每次递归的时候,要保证函数的实参是逐渐逼近结束条件的。
如果上述条件不能满足,就会出现“无限递归”,这是一种典型的代码错误。


