『无为则无心』Python函数 — 26、Python函数参数的传递方式

时间:2021-09-08 22:49:38

提示:上一篇文章介绍了Python中函数的基本使用,本篇文章主要说明一下Python函数实参的传递方式

1、位置参数

位置参数:调用函数时根据函数定义的参数位置来传递参数。

def user_info(name, age, gender):
print(f'您的名字是{name}, 年龄是{age}, 性别是{gender}') # 调用函数
user_info('TOM', 20, '男')

注意:传递和定义参数的顺序及个数必须一致。就是将对应位置的实参复制给对应位置的形参,第一个实参赋值给第一个形参,第二个实参赋值给第二个形参,以此类推。

示例

def user_info(name, age, gender):
print(f'您的名字是{name}, 年龄是{age}, 性别是{gender}') # 1.调用函数,传递的参数个数不正确
# 结果:TypeError: user_info() missing 1 required positional argument: 'gender'
user_info('TOM', 20) # 2.调用函数,传递的参数的顺序不正确
# 不会报错,但输出的内容完全歧义。
# 结果:您的名字是男, 年龄是TOM, 性别是20
user_info('男', 'TOM', 20)

2、关键字参数

可以不按照形参定义的顺序去传递,而直接根据参数名去传递参数。

函数调用,通过键=值形式加以指定。

可以让函数更加清晰、容易使用,同时也清除了参数的需求。

def user_info(name, age, gender):
print(f'您的名字是{name}, 年龄是{age}, 性别是{gender}') # 正确用法
user_info('Rose', age=20, gender='女')
user_info('小明', gender='男', age=16) # 位置参数必须写在关键字参数的前面
# 结果:SyntaxError: positional argument follows keyword argument
user_info(gender='男', age=16, "孙悟空") # 位置参数必须写在关键字参数的前面,同时位置参数的顺序也要对应
# 结果:TypeError: user_info() got multiple values for argument 'age'
user_info("孙悟空", '男', age=16) # 格式正确,但是位置参数的顺序不正确,结果也会产生歧义。
# 结果:您的名字是20, 年龄是孙悟空, 性别是男
user_info(20, "孙悟空", gender='男') """
总结:定义参数时,位置参数和关键字参数,尽量统一使用一种。
"""

注意:

  • 位置参数和关键字参数可以混合使用。
  • 函数调用时,如果有位置参数时,位置参数必须在关键字参数的前面,但关键字参数之间不存在先后顺序。

3、缺省参数(默认参数)

缺省参数也叫默认参数,用于定义函数时,为参数提供默认值,调用函数时可不传该默认参数的值。

提示:所有位置参数必须出现在默认参数前(因为默认参数的格式和关键字参数格式一样,所以都要写在所有参数之后),包括函数定义和调用。

def user_info(name, age, gender='男'):
print(f'您的名字是{name}, 年龄是{age}, 性别是{gender}') # 没有为缺省参数传值,表示使用默认值。
user_info('TOM', 20)
# 为缺省参数传值,使用这个值,即修改了默认值。
user_info('Rose', 18, '女')

注意:函数调用时,如果为缺省参数传值则修改默认参数值,否则使用这个默认值。

4、不定长参数(可变参数)

不定长参数也叫可变参数。用于不确定调用的时候会传递多少个参数(不传参也可以)的场景。此时,可用包裹位置参数,或者包裹关键字参数,来进行参数传递,会显得非常方便。

(1)包裹位置传递

"""
1.在定义函数时,可以在形参前边加上一个*,这样这个形参将会获取到所有的实参,
它将会将所有的实参保存到一个元组中
2.*args说明:*一定要写,args表示形参,可以自定义名称。
但在实际工作中,一般默认使用*args做为不定长包裹位置传递参数的表示,不做修改。
"""
def user_info(*args):
print(args) # ('TOM',)
user_info('TOM')
# ('TOM', 18)
user_info('TOM', 18)
# ()
user_info()

注意:传进的所有参数都会被args变量收集,它会根据传进的所有的位置实参,合并为一个元组(tuple),args是元组类型,这就是包裹位置传递。(这个过程也叫装包或者组包)

小应用

# 定义一个函数,可以求任意个数字的和
def sum(*nums):
# 定义一个变量,来保存结果
result = 0
# 遍历元组,并将元组中的数进行累加
for n in nums:
result += n
print(result) sum(123, 456, 789, 10, 20, 30, 40)

注意事项

# 注意事项1
# 带星号的形参只能有一个
# 带星号的参数,可以和其他参数配合使用
# 第一个参数给a,第二个参数给b,剩下的都保存到c的元组中
def fn2(a, b, *c):
print('a =', a)
print('b =', b)
print('c =', c) fn2(1, 2, 3, 4, 5)
"""
输出结果:
a = 1
b = 2
c = (3, 4, 5)
""" # 注意事项2
# 可变参数不是必须写在最后,但是注意,
# 带*的参数后的所有参数,必须以关键字参数的形式传递
# 第一个参数给a,剩下的位置参数给b的元组,c必须使用关键字参数
def fn2(a, *b, c):
print('a =', a)
print('b =', b)
print('c =', c)
# TypeError: fn2() missing 1 required keyword-only argument: 'c'
# fn2(1, 2, 3, 4, 5) # 报错
fn2(1, 2, 3, 4, c=5)
"""
输出结果:
a = 1
b = (2, 3, 4)
c = 5
""" # 注意事项3
# 所有的位置参数都给a,b和c必须使用关键字参数,
# 且必须写在最后。
def fn2(*a, b, c):
print('a =', a)
print('b =', b)
print('c =', c) fn2(1, 2, 3, b=4, c=5)
"""
输出结果:
a = (1, 2, 3)
b = 4
c = 5
""" # 注意事项4
# 如果在形参的开头直接写一个*,
# 则要求我们的所有的参数必须以关键字参数的形式传递。
def fn2(*, a, b, c):
print('a =', a)
print('b =', b)
print('c =', c) fn2(a=3, b=4, c=5)
"""
输出结果:
a = 3
b = 4
c = 5
""" # 注意事项5
# *形参只能接收位置参数,而不能接收关键字参数
def fn3(*a):
print('a =', a)
# TypeError: fn3() got an unexpected keyword argument 'a'
fn3(a=3, b=4, c=5)

(2)包裹关键字传递

"""
**kwargs说明:**一定要写,args表示形参,可以自定义名称。
但在实际工作中,一般默认使用**kwargs做为不定长包裹关键字传递参数的表示,不做修改。
"""
# 收集所有关键字参数,它会将这些参数统一保存到一个字典中返回。
# 字典的key就是参数的名字,字典的value就是参数的值
def user_info(**kwargs):
print(kwargs) # {'name': 'TOM', 'age': 18, 'id': 110}
# 关键字不能加引号,应为关键字对应的是形参。
user_info(name='TOM', age=18, id=110) # 包裹关键字传递只能有一个,并且必须写在所有参数的最后
# 实参可以不按顺序传递
def fn3(b, c, **a):
print('a =', a, type(a))
print('b =', b)
print('c =', c) fn3(e=10, b=1, d=2, c=3, f=20)
"""
输出结果:
a = {'e': 10, 'd': 2, 'f': 20} <class 'dict'>
b = 1
c = 3
"""

综上:无论是包裹位置传递还是包裹关键字传递,都是一个组包的过程(组包简单的说,就是收集分散的参数,返回一个整体数据)。关于组包对应就是拆包,在之前的文章【Python元组】中有介绍,可以对应的查看。

5、位置参数、默认参数、可变参数的混合使用

参数定义与调用顺序的基本原则是:位置参数,默认参数,包裹位置,包裹关键字。(定义和调用都应遵循)

提示:默认参数与包裹位置参数可以根据需求进行位置调换。

def user_info(name, age, sex=1, *args, **kargs):
print name, age, sex, args, kargs user_info('tanggu', 25, 2, 'music', 'sport', class=2) # 输出结果
# tanggu 25 1 ('music', 'sport') {'class'=2}

6、拓展:参数解包

关于组包对应就是拆包,在之前的文章【Python元组】中有介绍,可以对应的查看。

(1)通过包裹位置对一个元组进行解包

操作方式:使用*号。

如下示例:

# 参数的解包(拆包)
def fn4(a, b, c):
print('a =', a)
print('b =', b)
print('c =', c) # 创建一个元组
t = (10, 20, 30) # 我们直接传递t,会报错
# TypeError: fn4() missing 2 required positional arguments: 'b' and 'c'
# fn4(t) # 而以前我们是这样拆包的
# fn4(t[0], t[1], t[2])
"""
输出结果:
a = 10
b = 20
c = 30
""" # *号拆包
# 传递实参时,也可以在序列类型的参数前添加星号,
# #这样他会自动将序列中的元素依次作为参数传递。
# 这里要求序列中元素的个数必须和形参的个数的一致
fn4(*t)
"""
输出结果:
a = 10
b = 20
c = 30
"""

(2)通过包裹关键字对一个字典进行解包

操作方式:使用**号。

如下示例:

# 参数的解包(拆包)
def fn4(a, b, c):
print('a =', a)
print('b =', b)
print('c =', c) # 创建一个字典
d = {'a': 100, 'b': 200, 'c': 300}
# 通过 **来对一个字典进行解包操作
# 字典中的key要和函数的形参一一对应。
fn4(**d)
"""
输出结果:
a = 100
b = 200
c = 300
"""