函数的参数

形参与实参介绍
函数的参数分为形式参数和实际参数,简称形参和实参:
形参即在定义函数时,括号内声明的参数。形参本质就是一个变量名,用来接收外部传来的值。
实参即在调用函数时,括号内传入的值,值可以是常量、变量、表达式或三者的组合:
| |
| res=my_min(1,2) |
| |
| |
| a=1 |
| b=2 |
| res=my_min(a,b) |
| |
| |
| res=my_min(10*2,10*my_min(3,4)) |
| |
| |
| a=2 |
| my_min(1,a,10*my_min(3,4)) |
在调用有参函数时,实参(值)会赋值给形参(变量名)。在Python中,变量名与值只是单纯的绑定关系,而对于函数来说,这种绑定关系只在函数调用时生效,在调用结束后解除。
形参和实参的使用
位置参数
位置即顺序,位置参数指的是按顺序定义的参数,需要从两个角度去看:
在定义函数时,按照从左到右的顺序依次定义形参,称为位置形参,凡是按照这种形式定义的形参都必须被传值
| |
| def register(name,age,sex): |
| print('Name:%s Age:%s Sex:%s' %(name,age,sex)) |
| |
| register() |
| |
| ''' |
| |
| |
| def register(name, age, sex): |
| print('Name:%s Age:%s Sex:%s' % (name, age, sex)) |
| |
| register(18, "男", "Xiao") |
| |
| ''' |
| |
| |
| def register(name, age, sex): |
| print('Name:%s Age:%s Sex:%s' % (name, age, sex)) |
| |
| register("Xiao", 18, "男") |
| |
在调用函数时,按照从左到右的顺序依次定义实参,称为位置实参,凡是按照这种形式定义的实参会按照从左到右的顺序与形参一一对应
关键字参数
在调用函数时,实参可以是key=value的形式,称为关键字参数,凡是按照这种形式定义的实参,可以完全不按照从左到右的顺序定义,但仍能为指定的形参赋值
| register(sex='male',name='lili',age=18) |
| Name:lili Age:18 Sex:male |
位置和关键字混合使用
需要注意在调用函数时,实参也可以是按位置或按关键字的混合使用,但必须保证关键字参数在位置参数后面,且不可以对一个形参重复赋值
| register('lili',sex='male',age=18) |
| register(name='lili',18,sex='male') |
| register('lili',sex='male',age=18,name='jack') |
默认参数
在定义函数时,就已经为形参赋值,这类形参称之为默认参数,当函数有多个参数时,需要将值经常改变的参数定义成位置参数,而将值改变较少的参数定义成默认参数。例如编写一个注册学生信息的函数,如果大多数学生的性别都为男,那完全可以将形参sex定义成默认参数
- 默认参数必须在位置参数之后
- 默认参数的值仅在函数定义阶段被赋值一次
| def register(name,age,sex='male'): |
| print('Name:%s Age:%s Sex:%s' %(name,age,sex)) |
默认参数的值通常应设为不可变类型
| def foo(n,arg=[]): |
| arg.append(n) |
| return arg |
| foo(1) |
| [1] |
| foo(2) |
| [1, 2] |
| foo(3) |
| [1, 2, 3] |
定义时就已经为参数sex赋值,意味着调用时可以不对sex赋值,这降低了函数调用的复杂度
| register('tom',17) |
| Name:tom Age:17 Sex:male |
| register('Lili',18,'female') |
| Name:Lili Age:18 Sex:female |
小结:
| 为了防止有些参数重复或者报错 -- 默认参数 |
| |
| def index(name,age,gender='男'): |
| print(f'{name}-{age}-{gender}') |
| |
| index('dream',18) |
| |
| index('hope',18,'女') |
无论是默认参数的位置还是关键字参数的位置,一定要在位置参数后面
可变长参数
参数的长度可变指的是在调用函数时,实参的个数可以不固定,而在调用函数时,实参的定义无非是按位置或者按关键字两种形式,这就要求形参提供两种解决方案来分别处理两种形式的可变长度的参数。
可变长位置参数(*args)
如果在最后一个形参名前加*
号,那么在调用函数时,溢出的位置实参,都会被*
接收,以元组的形式保存下来赋值给该形参
| def foo(x,y,z=1,*args): |
| print(x) |
| print(y) |
| print(z) |
| print(args) |
| |
| foo(1,2,3,4,5,6,7) |
| |
| 1 |
| 2 |
| 3 |
| (4, 5, 6, 7) |
如果我们事先生成了一个列表,仍然是可以传值给*args的
| def foo(x,y,*args): |
| print(x) |
| print(y) |
| print(args) |
| |
| L=[3,4,5] |
| foo(1,2,*L) |
| 1 |
| 2 |
| (3, 4, 5) |
注意:如果在传入L时没有加*,那L就只是一个普通的位置参数了
| def foo(x, y, *args): |
| print(x) |
| print(y) |
| print(args) |
| L = [3, 4, 5] |
| foo(1, 2, L) |
| |
| |
| |
| |
| |
如果形参为常规的参数(位置或默认),实参仍可以是*的形式
| def foo(x,y,z=3): |
| print(x) |
| print(y) |
| print(z) |
| |
| foo(*[1,2]) |
| 1 |
| 2 |
| 3 |
如果我们想要求多个值的和,*args
就派上用场了
| def index(*args): |
| start = 0 |
| for i in range(len(args)): |
| start += args[i] |
| print(start) |
| |
| |
| index(1, 2, 3) |
可变长关键词参数(*kwargs)
- 如果在最后一个形参名前加
**
号,那么在调用函数时,溢出的关键字参数,都会被 **
接收,以字典的形式保存下来赋值给该形参
- 可变长关键字参数 : 传实参的时候要按照关键字去传
| def foo(x, **kwargs): |
| print(x) |
| print(kwargs) |
| |
| |
| foo(y=2, x=1, z=3) |
| |
| |
| |
- 如果我们事先生成了一个字典,仍然是可以传值给
**kwargs
的
| def foo(x, y, **kwargs): |
| print(x) |
| print(y) |
| print(kwargs) |
| |
| |
| dic = {'a': 1, 'b': 2} |
| foo(1, 2, **dic) |
| |
| |
| |
| |
| |
| |
- 如果在传入 dic 时没有加
**
,那 dic 就只是一个普通的位置参数了
| def foo(x, y, **kwargs): |
| print(x) |
| print(y) |
| print(kwargs) |
| |
| |
| dic = {'a': 1, 'b': 2} |
| foo(1, 2, dic) |
| ''' |
| Traceback (most recent call last): |
| File "E:\PythonProjects\01.py", line 358, in <module> |
| foo(1, 2, dic) |
| TypeError: foo() takes 2 positional arguments but 3 were given |
| ''' |
- 如果形参为常规参数(位置或默认),实参仍可以是
**
的形式
| def foo(x, y, z=3): |
| print(x) |
| print(y) |
| print(z) |
| |
| |
| foo(**{'x': 1, 'y': 2}) |
组合使用
| def register(name, age, *args, **kwargs): |
| user_dict = {'name': name, 'age': age} |
| |
| if args: |
| user_dict['additional_info'] = args |
| |
| if kwargs: |
| user_dict.update(kwargs) |
| return user_dict |
| |
| |
| user_dict = register("Xiao", 18, "handsome",'music', hobby=["music"]) |
| print(user_dict) |
命名关键字参数
| 在函数定义形参时,如果出现 * 隔断两边的形参,前面的参数任意(可位置/可关键字), * 后面的参数必须按照关键字传参数 |
| def login(name,pwd,*,hobby,sex): |
| print(f'{name}-{pwd}-{hobby}-{sex}') |
| login('dream', '521', hobby='music', sex='男') |
| |
| |
| |
| def login(name, pwd, *, hobby='music', sex): |
| print(f'{name}-{pwd}-{hobby}-{sex}') |
| |
| |
| login('xiao', '000', sex='男') |
| login('xiao', '000', hobby='swim', sex='男') |
| - * 号后面的参数必须用关键字命名,* 前面任意使用 |
| - 需要在定义形参时,用 * 作为一个分隔符号,* 号之后的形参称为命名关键字参数。 |
| - 对于这类参数,在函数调用时,必须按照 key=value 的形式为其传值,且必须被传值 |
以上所有参数混合使用
- 综上所述所有参数可任意组合使用,但定义顺序必须是:
位置参数
、默认参数
、*args
、命名关键字参数
、**kwargs
- 可变参数
*args
与关键字参数**kwargs
通常是组合在一起使用的
- 如果一个函数的形参为
**args
与**kwargs
,那么代表该函数可以接收任何形式、任意长度的参数
| def wrapper(*args,**kwargs): |
| pass |
- 在该函数内部还可以把接收到的参数传给另外一个函数(这在装饰器的实现中大有用处)
| def func(x, y, z): |
| print(x, y, z) |
| |
| |
| def wrapper(*args, **kwargs): |
| func(*args, **kwargs) |
| |
| |
| wrapper(1, z=3, y=2) |
| |
- 提示:
*args
、**kwargs
中的 args 和 kwargs 被替换成其他名字并无语法错误,但使用args、kwargs是约定俗成的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏