函数
一、函数的引入和介绍
- 一个项目中往往有着许多的功能需要实现,而有些功能的代码需要重复使用,每次使用都要在复现一遍,这样会使得代码变的冗长
- 当某个功能代码需要修改时,我们又需要找出整个程序中使用过的地方进行修改,这样的代码维护起来也非常难
- 所以我们就需要一个能整合这些功能并且随时能够使用的东西,函数就是这样的,通过函数的定义提前写好需要的功能,需要时可以调用这个函数。
二、函数的定义和调用
-
函数的使用必须遵循’先定义,后调用’的原则。
-
定义函数的语法
def 函数名(参数1,参数2,...): """文档描述""" 函数体 return 值
[1]函数的定义
(1)空函数
def login():
...
(2)无参数无返回值的函数
def login():
user_name = input("请输入你的用户名:")
pass_word = input("请输入你的用户名:")
#只是单纯的输入
(3)有参数无返回值的函数
user_name = input("请输入你的用户名:")
pass_word = input("请输入你的用户名:")
def login(username, password):
...
# 调用函数时需要输入变量(值)
(4)无参数有返回值的函数
def login():
user_name = input("请输入你的用户名:")
pass_word = input("请输入你的用户名:")
return user_name, pass_word
#调用函数时,会返回你输出的值,可以使用变量去接收
(5)有参数有返回值的函数
dict_pwd = {"Xanadu": "521"}
user_name = input("请输入你的用户名:")
pass_word = input("请输入你的用户名:")
def login(user_name, pass_word):
if dict_pwd[user_name] == pass_word:
print("登录成功!")
return "True"
result = login(user_name, pass_word)
print(result)
'''
登录成功!
True
'''
(6)多返回值和多个参数的函数
def add(a, b):
return a + b, a * b
result_1, result_2 = add(2, 4)
print(result_1) # 6
print(result_2) # 8
[2]函数的三种调用方式
[1]直接调用
- 直接使用函数名调用函数
def add(x, y):
return x + y
#直接使用add调用
result = add(1, 3)
print(result) # 4
[2]表达式调用
- 将函数地址传给变量,使用变量去实习函数功能
def add(x, y):
return x + y
method = add # 将函数地址传给变量method
result = method(1, 3) # 然后再调用
print(result) # 4
[3]函数作为参数
- 可以将函数的值或者内存地址作为参数使用
def add(x, y):
return x + y
def method(func, x, y):
return func(x, y)
result = method(add, 1, 3) # 我们将add 函数的内存地址作为参数,这样method函数中就可以直接调用add函数
print(result) # 4
三、函数的参数
[1]函数参数的介绍
(1)形参
- 在定义函数时,在括号内声明的参数(其本质是一个变量名用于接收来自外部的值)
(2)实参
- 在调用函数时,传入函数的值(可以是常量、变量、表达式或者三者的组合)
def add(x, y, z=3):
print(x + y)
#实参是常量
add(1, 2) # 3
x = 1
y = 2
#实参是变量
add(x, y) # 3
x = 1
y = 2
#实参可以是表达式
add(x * 3, y + 1) # 6
def add(a, b):
return a + b
#实参可以是任意组合的
print(add((x + 3) * 2, add(x, y))) # 11
[2]位置参数
-
将参数传入函数时有两种方式,一种是按照函数定义时形参的位置顺序传入,一一对应;另一种是按照形参的关键字传入参数
-
位置参数就是按照位置传入的参数,只要是按照位置传参的使用定义的形式参数都必须传入对应的值
(1)有位置参数但没有传值时汇报错
def add(x, y, z):
return x + y + z
#少传了一个位置参数z
print(add(1, 2)) # TypeError: add() missing 1 required positional argument: 'z'
(2)不按照顺序传递参数会导致数据错误
def msg(name, age, sex):
print(f"name : {name}, age : {age}, sex : {sex}")
# name : 18, age : male, sex : Xanadu 不按照顺序传值导致数据错乱
msg("18", "male", "Xanadu")
[3]关键字参数
- 在调用函数时以“key =value”的形式传入实参,这样形式的参数就是关键字参数
def msg(name, age, sex):
print(f"name : {name}, age : {age}, sex : {sex}")
#关键字传参就不需要严格按照顺序
msg(age="18", sex="male", name="Xanadu") # name : Xanadu, age : 18, sex : male
[4]默认参数
-
在定义函数时,就已经为形参赋值,这类参数就是默认参数,有默认参数时,就可以不传入这个参数,会默认赋值定义函数时给的值
- 默认参数在形参的位置要在一般形式参数的最后,不然会报错
- 一般将传入的值一般不便会很少变化的参数赋值为默认参数,如当一个班级内大部分都是男生时,性别这一参数就可以赋值为男的默认参数
def msg(name, age, sex="male"): print(f"name : {name}, age : {age}, sex : {sex}") #有默认参数时可以不传值,默认参数就是默认值 msg(age="18", name="Xanadu") # name : Xanadu, age : 18, sex : male def msg(hobby, hobby_list=[]): hobby_list.append(hobby) return hobby_list # 默认参数的值通常应设为不可变类型 # 每次调用是在上一次的基础上向同一列表增加值 msg("sing") msg("dance") data = msg("basketball") print(data) # ['sing', 'dance', 'basketball']
四、可变长参数
-
参数的长度可变是指在向函数内传递参数时,其个数时不固定的
-
而我们传递参数的方法又分为位置传参和关键字传参两种,就有各自的可变长位置参数和可变长关键字参数两种
[1]可变长位置参数
(1)任意类型参数
-
当在传入参数时,在最后一个位置参数前加上
*
时,传入参数时溢出的参数都会被这个参数以元组的形式保留。def add(x, y, *args): print(x) print(y) print(args) add(1, 2, 3, 4, 5, 6) ''' 1 2 (3, 4, 5, 6) # 溢出的数字都被*args以元组的形式保留 '''
-
我们也可以通过
*
加上可迭代对象将对象中的元素分别传给函数内不同的参数def add(x, y, z): print(x + y + z) add(*[1, 2, 3]) # 6
-
以
*
加上变量名的方式可以将多个变量输入以元组的输入同一个参数def add(*args): print(args, end=' ') x = 0 for i in args: x += i print(x) add(1, 2, 3, 4) # (1, 2, 3, 4) 10
(2)解包
- 可以将可迭代对象以变量传入可变长位参数,保存为元组形式
def add(x, y, *args):
print(x, end=' ')
print(y, end=' ')
print(args)
list_1 = [3, 4, 5]
add(1, 2, *list_1) # 1 2 (3, 4, 5)
[2]可变长关键字参数(**kwargs)
- 当在传入参数时,在最后一个位置参数前加上
**
时,传入参数时溢出的参数都会被这个参数以字典的形式保留。
def add(x, **kwargs):
print(x, end=' ')
print(kwargs)
add(x=1, y=2, z=3) # 1 {'y': 2, 'z': 3}
- 可以将字典传入可变长关键字参数,但要在其前面加上
**
,不然会报错
dict_1 = {"name": "Xanadu", "age": 18}
def msg(**kwargs):
print(kwargs)
msg(**dict_1) # {'name': 'Xanadu', 'age': 18}
- 我们也可以通过
**
加上字典将对象中的元素分别传给函数内不同的参数
dict_1 = {"name": "Xanadu", "age": 18}
def msg(name, age):
print(name, end=' ')
print(age)
msg(**dict_1) # Xanadu 18
五、命名关键字参数
[1]函数内判断
- 如果有多个
key:value
键值对通过可变关键字传入函数内部,我们可以在函数内判断某个键值对是否存在。
def msg(**kwargs):
if "name" in kwargs:
print("name在字典内", end=" ")
if "age" in kwargs:
print("age在字典内")
dict_1 = {"name": "Xanadu", "age": 18}
msg(**dict_1) # name在字典内 age在字典内
[2]命名关键字传参
- 想要限定函数的调用者必须以key=value的形式传值,可以在函数定义式在形式参数输入的以
*
作为分隔符,*后面的都要以键值对的方式传入参数,都变成了关键字参数,要以键值对传参不然就会报错。
def msg(name, *, age, sex):
print(name, end=' ')
print(age, end=' ')
print(sex)
dict_1 = {"age": 18, "sex": "男"}
msg(name='Xanadu', **dict_1) # Xanadu 18 男
[3]命名关键字参数和命名关键字参数默认值
- 命名关键字参数也可以有默认值,简化调用。
def msg(name, age, sex, height=185):
print(f"{name}-{age}-{sex}-{height}")
dict_1 = {"name": "Xanadu", "age": 18}
msg(**dict_1, sex="男") # Xanadu-18-男-185
-
需要强调的是:sex不是默认参数,height也不是位置参数
-
因为二者均在
*
后,所以都是命名关键字参数,形参sex=’male’属于命名关键字参数的默认值,因而即便是放到形参height之前也不会有问题。 -
另外,如果形参中已经有一个
*args
了,命名关键字参数就不再需要一个单独的*
作为分隔符号了
-