11. 函数的参数
1. 函数的概念与定义
1.1 概念
循环的本质:在相同的地方反复执行相同的代码
函数的本质:在不同的地方反复执行相同的代码
1.2 语法
def 函数名(参数1,参数2):
"""函数的注释"""
函数体代码
return 返回值
1. def:是定义函数的关键字
2. 函数名:函数名类似于变量名,指代函数体代码,
命名与变量名一致(字母、数字、下划线、数字不能开头;下划线形式、驼峰体形式)
类似于数学函数中的 h(x)的h, f(x)的f
3. 括号:定义函数的时候,函数名后面一定要有括号
4. 参数:类似于使用函数的时候,给函数内部传递的数据,可以不写,或者单个、多个
有点像数学函数中f(x)的x
5. 冒号:定义函数也需要有缩进的代码块
6. 函数的注释:用于解释函数的主要功能、使用说法等说明性文字
7. 函数体代码:函数的核心功能
有点像数学函数中f(a)右侧的函数式 f(a,b) = a + b
8. return:后面跟什么,函数执行完成后就会返回什么
定义函数不会执行函数体代码,但是会检测语法
# 1.函数的基本定义
def f1():
a = 1 +1
f1()
print(f1()) # None
# 2.有一个参数但是没有返回值的函数
def f2(name):
b = 1 + 2
f2('messi') #
print(f2('messi')) # None
# 3.有多个参数但是没有返回值
def f3(x, y):
res = x + y
# 函数调用的时候,定义几个参数就必须传几个参数
f3(333, 666)
print(f3(333, 666)) # None
# 4.有参数有返回值的函数
def f4(a, b):
res2 = a * b
return res2
print(f4(9, 9)) # 81
1.3 函数的调用
(1)直接调用
根据函数名调用函数
(2)间接调用
用新的变量名来存储原本函数的内存空间地址,然后再调用原本的函数
def f(x, y):
return x * y
print(f) # <function f at 0x0000024F50773E20>
# 可以将函数名赋值给其它变量名
h = f
print(h(16, 16)) # 256
(3)表达式调用
在函数的返回值中如果只有一个返回值就是该值本身的类型
如果有多个返回值,返回的结果是一个元组---解压赋值
def f1(x, y):
return x + y
print(f1(11, 22),type(f1(11, 22))) # 33 <class 'int'>
def f2(a, b):
res1 = a + b
res2 = a * b
return res1, res2
print(f2(3, 3),type(f2(3, 3))) # (6, 9) <class 'tuple'>
1.4 函数的返回值
函数体代码里面写return相当于循环体代码里面写break,遇到了就会立刻结束函数和循环的执行
如果写的是变量名就返回变量名指向的值
函数的返回值可以被其它变量接收
函数的返回值可以被其它函数接收
def f1(a, b):
return a + b
def f2(x, y):
return x * y
print(f2(f1(1,2), 10)) # 30
1.5 函数作为参数
def get_name_pwd():
name = input("请输入名字: ")
pwd = input('请输入密码')
return name, pwd
def login():
login_name, login_pwd = get_name_pwd()
if login_name == 'messi' and login_pwd == '001':
print('登录成功')
else:
print('登录失败')
def regi():
regi_name, regi_pwd = get_name_pwd()
print(f'用户{regi_name}注册成功')
-------------------------------------------------------------------
choice = """
***功能菜单***
1.注册
2.登录
"""
func_dict = {
'1': regi, # 函数名regi即函数regi的内存地址
'2': login # 函数名login即函数login的内存地址
}
while True:
print(choice)
id = input('请输入功能id:')
if id not in func_dict:
print('你的输入有误')
continue
f1 = func_dict.get(id)
# f1可以是regi的内存地址,也可能是login的地址
f1()
之前的写法
while True:
print(choice)
id = input("请输入功能ID :>>>> ").strip()
if id == '1':
regi()
elif id == 2:
login()
2. 函数的参数
2.1 形参与实参
形参:函数在定义阶段括号内写的参数,称之为形式参数
实参:函数在调用阶段括号内写的参数,称之为实际参数
形参类似于变量名,实参类似于变量值
在调用函数的时候传入实参,会与形参临时绑定,函数运行结束之后自动解除绑定
def f1(x, y): # x和y就是f1函数的形参
print(x + y)
f1(11, 22) # 11和22就是f1函数的实参
2.2 位置参数和关键字参数
位置参数
位置形参:在函数定义阶段括号内从左往右依次填写的变量名
位置实参:在函数调用阶段括号内从左往右依次传入的数据
在调用的时候参数个数要相等,顺序不能乱
关键字参数
出现在实参中,用变量的方式给函数传参,与顺序无关
def f1(x, y):
print(x + y)
f1(x=11, y=22) # 33
f1(y=2, x=3) # 5
位置参数与关键字参数混用
def f1(x, y):
print(x + y)
f1(y=111, 222) # 报错,关键字参数必须放在位置参数的后面
f1(333, x=444) # 报错,形参只能指向一个实参,形参x重复绑定值
2.3 默认参数
在函数的定义阶段给变量名赋一个初始的值
如果该变量被传入新的值,则初始值会被新值覆盖
如果该变量没有被传入新的值,则还是使用初始的默认值
默认参数必须放在位置参数后面
def player(name, num, club='psg'):
print(f'球员{name}号码{num}球队{club}')
player('messi', 1)
player('kylian', 2)
player('ronaldo', 3,'realmadrid')
# 球员messi号码1球队psg
# 球员kylian号码2球队psg
# 球员ronaldo号码3球队realmadrid
默认参数的特殊情况
a = []
def app_element(num):
a.append(num)
return a
print(app_element(1)) # [1]
print(app_element(2)) # [1, 2]
print(app_element(3)) # [1, 2, 3]
----------------------------------------------------------
def app_element(num, a=[]):
a.append(num)
return a
# 因为列表是可变数据类型所以 在每次添加新的元素后影响到的都是原本的列表
# 列表中添加 1 2 3 ---> [1,2,3]
print(app_element(1)) # [1]
print(app_element(2)) # [1, 2]
print(app_element(3)) # [1, 2, 3]
def app_element(num, a=None):
if not a:
a = []
a.append(num)
return a
print(app_element(1)) # [1]
print(app_element(2)) # [2]
print(app_element(3)) # [3]
2.4 可变长参数
需求:定义一个函数,无论穿多少位置实参都可以正常执行
可变长位置参数
*号在形参中,可以接收多余的位置参数,组成元组的形式赋值给*号后后面的变量名
推荐写法 *args
def f1(a, b, *args):
print(a, b)
print(args)
f1(1, 2, 3, 4)
# 1 2
# (3, 4)
*号是压缩与解压的意思
a = [1, 2, 3]
print(a) # [1, 2, 3]
print(*a) # 1 2 3
def f1(name, num):
print(f'球员{name}')
print(f'号码{num}')
info = ['messi', '001']
f1(*info)
# 球员messi
# 号码001
**号在形参中,用于接收多余的关键字参数,组成字典的形式赋值给**后面的变量名
推荐写法 **kwargs
def add(x, y, *args, **kwargs):
print(x, y)
print(args)
print(kwargs)
add(1, 2, 3, 4, 5, a=666, b=999)
# 1 2
# (3, 4, 5)
# {'a': 666, 'b': 999}
2.5 命名关键字参数
2.5.1 概念
想要限定函数的调用者必须以key=value的形式传值
Python3提供了专门的语法:
def add(x, y, *, z):
print(z)
add(11, 22, z=33) # 33
没以key=value传值会报错
没传值也会报错
def handle_info(name, age, *, gender, hobby): # gender,hobby为命名关键字参数
pass
# 正确调用
handle_info('messi', 37, gender='male', hobby='soccer')
# 未使用关键字进行传值
handle_info('messi', 37, male, soccer) # NameError: name 'male' is not defined. Did you mean: 'False'?
# 传少了值
handle_info('messi', 37, gender='male') # TypeError: handle_info() missing 1 required keyword-only argument: 'hobby'
2.5.2 命名关键字参数默认值
命名关键字参数也可以有默认值,从而简化调用
def handle_info(name, age, *, hobby='soccer', gender):
print(f'Name:{name}, Age:{age}, Hobby:{hobby}, Gender:{gender}')
handle_info('messi', 20, gender='male')
# Name:messi, Age:20, Hobby:soccer, Gender:male
需要强调的是,hobby不是默认参数,gender也不是位置参数
因为二者都在 * 号之后,所以都是命名关键字参数,形参hobby='soccer属于命名关键字参数的默认值,因而即便是放到形参gender之前也不会有问题
另外,如果形参中已经有了一个 * args了,命名关键字参数就不再需要一个单独的 * 作为分隔符号
def handle_info(name, age, *args, hobby='soccer', gender):
print(f'Name:{name}, Age:{age}, Args:{args}, Hobby:{hobby}, Gender:{gender}')
# hobby与gender仍为命名关键字参数
handle_info('messi', 20, 1, 2, 3, 4, 5, 6, gender='male')
# Name:messi, Age:20, Args:(1, 2, 3, 4, 5, 6), Hobby:soccer, Gender:male
2.5.3 函数内判断
在定义了**kwargs参数后,函数调用者就可以传入任意的关键字参数key=value
如果函数体代码的执行需要依赖某个key,必须在函数内进行判断
def regi(name, age, **kwargs):
if 'gender' in kwargs: # 有gender参数
pass
if 'hobby' in kwargs: # 有height参数
pass