python 函数的参数(笔记整理)
一、形参与实参介绍
- 函数的参数分为形式参数和实际参数:简称形参和实参
- 在定义函数阶段依次填写的参数名字,称为:形式参数(也称为形参)作为函数的输入,以便在函数内部进行处理。
- 而在调用函数阶段,函数名括号中需要传入具体的值作为实际参数(也称为实参),这些实参会被赋值给函数中的形参,并作为函数的输入。
- 在调用有参函数时,实参(值)会赋值给形参(变量名)。
- 实参对于函数来说,实参与形参的这种绑定关系只在函数调用时生效,在调用结束后解除。
1. def add(a, b):# 在定义阶段时,写在函数名括号里的称为:形参 用来接收外部传来的值
return a + b
""" a 和 b 是函数的形参,它们可以被看做是函数内部的变量名。当我们调用该函数时,必须传入两个具体的整数值"""
2. result = add(3, 5)#在调用阶段,函数名后面括号中的参数称为实参 值可以是常量、变量、表达式或三者的组合
print(result) # 输出 8
""" 3 和 5 是函数 add() 的实参。当函数被调用时,这两个实参分别被赋值给 a 和 b,并且计算它们的和。最后,函数 add() 返回计算结果 8,并被赋值给变量 result,随后被输出。"""
3.实参是常量
res=my_min(1,2)
4.实参是变量
a=1
b=2
res=my_min(a,b)
5.实参是表达式
res=my_min(10*2,10*my_min(3,4))
6.实参可以是常量、变量、表达式的任意组合
a=2
my_min(1,a,10*my_min(3,4))
二、形参与实参的具体使用
1. 位置参数
- 位置也就是顺序,位置参数是指按照函数定义中的顺序依次传入的实参,也就是第一个形参对饮第一个实参以此类推。。。
- 在定义函数时,按照从左到右的顺序依次定义形参,称为:位置形参,凡是按照这种形式定义的形参都必须传实参
- 在调用函数时,按照从左到右的顺序依次定义实参,称为位置实参,凡是按照这种形式定义的实参会按照从左到右的顺序与形参一一对应
def add(a, b):
return a + b
result = add(3, 5) # 位置参数 3 和 5 按照位置顺序传入
print(result) # 输出 8
add() #函数接受两个位置参数 a 和 b,并按照从左到右的顺序进行传递。在调用 add() 函数时,传入的实参为 3 和 5,这两个实参分别被赋值给形参 a 和 b,并且计算它们的和。
2. 关键字参数
- 关键字参数:就是在调用阶段,通过形参名指定一个实参
- 实参是key=value的形式,称为关键字参数,就是定义好形参名字之后,在实参那里通过 **" 形参名 = 指定的实参 " **不需要按照左右顺序传递,指定实参是啥,他就是啥
- 调用函数时,实参可以是按位置或者按关键字给形参赋值,但是必须保证关键字参数在位置参数后面,而且同一个形参不可以重复赋值,会报错
def add(a, b):
return a + b
result = add(b=5, a=3) # 关键字参数以形参名=实参的方式进行传递
print(result) # 输出 8
调用 add() 函数时,通过形参名显式指定了实参 a=3 和 b=5,这两个实参并不按照函数定义中的顺序进行传递。在函数内部,这两个实参分别被赋值给形参 a 和 b,并且计算它们的和。
3. 默认参数
- 默认参数:就是在定义阶段,在函数名括号中定义一个默认的实参
- 定义好了默认参数,可以不用传实参,若是传了实参,会把默认参数按照位置顺序替换成你传的实参
- 默认参数必须在位置参数之后
- 默认参数的值仅在函数定义阶段被赋值一次,后面就无法改变了
- 默认参数的值通常应设为不可变类型 ,每次调用是在上一次的基础上向同一列表增加值
def add(a, b=0): # 形参 b 默认值为 0
return a + b
result1 = add(3) # 未传递实参 b,使用默认值 0
result2 = add(3, 5) # 实参 3 和 b=5 按照位置顺序传递
print(result1) # 输出 3
print(result2) # 输出 8
定义了一个 add() 函数,并给形参 b 赋予默认值 0。当在调用 add() 函数时没有传递实参 b 时,会使用默认值 0。例如,result1 的计算结果为 3,而 result2 的计算结果为 8。
"""需要注意的是,在使用默认参数时,必须将默认参数定义在位置参数之后,否则会出现语法错误。"""
1.正确示例
def add(a, b=0):
return a + b
2.错误示例,会产生语法错误
def add(b=0, a):
return a + b
4. 不定长参数(*args与kwargs**的用法)
- 什么是不定长参数:实参的个数可以不固定可以有很多,简单解释“在调用函数时,实参的定义无非是按位置或者按关键字两种形式,不定长就解决了一种形式可以直接传递不经常使用的形参”
- Python 中提供了两种不定长参数,分别是 *args 和 **kwargs。默认是这样写,但是后面的不一定非要是 args 或 kwasgs,可以改的
*args (不定长位置参数)
*args 用于接收任意数量的位置参数,在最后一个形参名前加 *args _那么在调用函数时,溢出的位置实参,都会被_接收,以元组的形式保存下来赋值给该形参
1.循环求多个值的和
def add(*nums):
result = 0 # 初始化计算结果为 0
for num in nums:
result += num
return result
result1 = add(3, 5, 7)
result2 = add(2, 4, 6, 8, 10)
print(result1) # 输出 15
print(result2) # 输出 30
定义了一个 add() 函数,并使用 *nums 形参来接收任意数量的位置参数。在函数内部,可以通过循环遍历这些位置参数,并将它们累加到计算结果中。
2.正常接收溢出的实参
def foo(x,y,z=1,*args): #在最后一个形参名args前加*号
print(x)
print(y)
print(z)
print(args)
foo(1,2,3,4,5,6,7) #实参1、2、3按位置为形参x、y、z赋值,多余的位置实参4、5、6、7都被*接收,以元组的形式保存下来,赋值给args,即args=(4, 5, 6,7)
1
2
3
(4, 5, 6, 7)
3.使用列表传给*args
def foo(x,y,*args):
print(x)
print(y)
print(args)
L=[3,4,5]
foo(1,2,*L) # *L就相当于位置参数3,4,5, foo(1,2,*L)就等同于foo(1,2,3,4,5)
1
2
(3, 4, 5)
4.如果在传入L时没有加*,那L就只是一个普通的位置参数了
foo(1,2,L) #仅多出一个位置实参L
1
2
([1, 2, 3],)
5.如果形参为常规的参数(位置或默认),实参仍可以是*的形式
def foo(x,y,z=3):
print(x)
print(y)
print(z)
foo(*[1,2]) #等同于foo(1,2)
1
2
3
**kwargs (不定长关键字参数)
**kwargs 用于接收任意数量的关键字参数,如果在最后一个形参名前加 **kwargs ,那么在调用函数时,溢出的关键字参数,都会被接收,以字典的形式保存下来赋值给该形参
1.组装数据
def print_info(**info):
for key, value in info.items():
print(f"{key}: {value}")
print_info(name="Alice", age=21)
print_info(username="bob", password="123456")
定义了一个 print_info() 函数,并使用 **info 形参来接收任意数量的关键字参数。在函数内部,可以通过遍历这些关键字参数,并打印其键值对。
2.正常接收实参给**kwargs
def foo(x,**kwargs): #在最后一个参数kwargs前加**
print(x)
print(kwargs)
foo(y=2,x=1,z=3) #溢出的关键字实参y=2,z=3都被**接收,以字典的形式保存下来,赋值给kwargs
1
{'z': 3, 'y': 2}
3.生成了一个字典,仍然是可以传值给**kwargs
def foo(x,y,**kwargs):
print(x)
print(y)
print(kwargs)
dic={'a':1,'b':2}
foo(1,2,**dic) #**dic就相当于关键字参数a=1,b=2,foo(1,2,**dic)等同foo(1,2,a=1,b=2)
1
2
{'a': 1, 'b': 2}
4.如果在传入dic时没有加**,那dic就只是一个普通的位置参数了
foo(1,2,dic) #TypeError:函数foo只需要2个位置参数,但是传了3个
5.如果形参为常规参数(位置或默认),实参仍可以是**的形式
def foo(x,y,z=3):
print(x)
print(y)
print(z)
foo(**{'x':1,'y':2}) #等同于foo(y=2,x=1)
1
2
3
5. 命名**kwargs (不定长关键字参数)
1.不使用命名关键字,就必须依赖 if 去判断
def register(name,age,**kwargs):
if 'sex' in kwargs:
#有sex参数
pass
if 'height' in kwargs:
#有height参数
pass
如果不是用命名关键字的话,而去使用**kwargs参数,函数调用阶段就可以传入任意的关键字参数key=value,但是代码的执行就需要依赖某个key,还必须在函数内进行判断
2.使用命名关键字
def register(name,age,*,sex,height): #sex,height为命名关键字参数
pass
register('lili',18,sex='male',height='1.8m') #正确使用
register('lili',18,'male','1.8m') # TypeError:未使用关键字的形式为sex和height传值
register('lili',18,height='1.8m') # TypeError:没有为命名关键字参数sex传值。
如果想限制必须以key=value的形式传值,需要在先使用"*"星号作为分隔符,之后在函数调用时,必须按照key=value的形式为其传值,且必须被传值
3.命名关键字参数也可以有默认值,从而简化调用
def register(name,age,*,sex='male',height):
print('Name:%s,Age:%s,Sex:%s,Height:%s' %(name,age,sex,height))
register('lili',18,height='1.8m')
运行结果:name:lili,Age:18,Sex:male,Height:1.8m
"""
前调:sex 和 height 既不是默认参数也不是位置参数,所以都是命名关键字参数
如果形参中已经有一个args了,命名关键字参数就不再需要一个单独的*作为分隔符号了
"""
4.如果添加了 args 的话被使用掉了那么后面的参数也是命名关键字
def register(name,age,*args,sex='male',height):
print('Name:%s,Age:%s,Args:%s,Sex:%s,Height:%s' %(name,age,args,sex,height))
register('lili',18,1,2,3,height='1.8m') #sex与height仍为命名关键字参数
执行结果Name:lili,Age:18,Args:(1, 2, 3),Sex:male,Height:1.8m
6. 所有参数可任意组合使用
- 综上所述所有参数可任意组合使用,定义顺序必须是:位置参数、默认参数、关键字、*args、命名关键字参数、kwargs**
- 可变参数args与关键字参数kwargs通常是组合在一起使用的
- 如果一个函数的形参为args与kwargs,那么代表该函数可以接收任何形式、任意长度的参数
- 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)
1 2 3
1. 位置实参1被*接收,以元组的形式保存下来,赋值给args,即args=(1,),关键字实参z=3,y=2被**接收,以字典的形式保存下来,赋值给kwargs,即kwargs={'y': 2, 'z': 3}
2. 执行func(args,kwargs),即func(*(1,),** {'y': 2, 'z': 3}),等同于func(1,z=3,y=2)