共计 3942 个字符,预计需要花费 10 分钟才能阅读完成。
一. 函数参数两大类
1. 什么是形参
- (形式参数 ):指的是在 定义 函数时,括号内定义的参数,形参其实就 变量名
2. 什么是实参
- (实际参数 ): 指的是在 调用 函数时,括号内传入的值,实参其实就 变量的值
3. 实参与形参的关系
-
在调用函数是时, 实参的值会绑定给形参, 该绑定关系可以在函数内使用
-
在函数调用结束后, 会立刻解除绑定关系
示例
🦢定义阶段
def func(x,y): # 此时的 "x,y" 是形参
print(x)
print(y)
🦢调用阶段
func(10,11) # 此时的 "10,11" 就是实参
二. 位置参数
1. 位置形参
- 在 定义函数时,按照从左到右的顺序依次定义的变量名,称之为位置形参
- 特点 : 必须被传值, 多一个不行, 少一个也不行
🦢定义阶段
def foo(x,y,z):
print(x,y,z)
🦢多一个或少一个都报错
foo(1,2) #少了一个数 报错
foo(1,2,3,4) #多了一个数 报错
🦢位置实参必须与形参一一对应
foo(1,2,3) # 1 2 3
2. 位置实参
- 在 调用函数时,按照从左到右的顺序依次传入的值,称之为位置实参
- 特点 : 按照位置与形参一一对应
def foo(x,y,z):
print(x,y,z)
foo(1,2,3) # 1 2 3
foo(3,2,1) # 3 2 1
3. 应用场景
- 对于 经常需要变化的值 , 需要将对应的形参定义成 位置形参
三. 默认参数
1. 什么是默认参数
- 具有默认值的形参
- 在 定义函数时,就已经为某个形参赋值了,该形参就称之为默认参数
- 特点 : 在调用阶段可以不用给默认参数传值
🦢定义阶段 "y" 的默认值就是 "1111"
def func(x,y=1111):
print(x,y)
🦢可以为 "y" 传值, 也可以不传值
func(1,2) # 1 2
func(1) # 1 1111
2. 默认参数的应用
- 保存多个人的信息
🦢大多数的是男性, 设置默认性别
def register(name,age,sex='male'):print(name,age,sex)
🦢有女性的就单独传入值就行, 减少了冗余
register('sss',14) #sss 14 male
register('ddd',18) #ddd 18 male
register('lll',74,'female') #111 74 female
register('nnn',54) #nnn 54 male
3. 默认形参与位置形参的组合使用
- 注意 : 位置形参必须在默认形参前
🦢正确写法
def func(x,y=1111):
print(x,y)
🦢错误写法
def func(y=1111,x):
print(x,y) # 报语法错误 (SyntaxError)
- 注意 2 : 默认参数只在定义阶段赋值一次, 这时就已经固定死了
🦢定义阶段 'y' 已经是 'm=10' 了, 不会再改变了
m=10
def foo(x,y=m)
print(x,y)
🦢再次定义也不会改变 'y' 的值
m='jhhhhjhj'
foo(1) # 1 10
foo(1,11) # 1 11
- 注意 2 : 默认形参的值最好是不可变类型
🦢先看看可变类型产生的结果
def register(name,hobby,l=[]):
l.append(hobby)
print(name,l)
register('wxx','play') # wxx ['play']
register('alex','read') # alex ['play','read']
register('egon','music') # alex ['play','read','music']
# 发现 "hobby" 都被杂在一起了, 原理就是指向的是同一个内存地址
🦢我们将默认形参设置成 "None"(不可变类型), 在函数体内部创建一个空列表, 那么这个空列表就是独属于个人的列表, 不受函数体外部的影响
def register(name,hobby,l=None):
if l is None:
l=[]
l.append(hobby) #l=['play']
print(name,l) # wxx ['play']
register('wxx','play') # wxx ['play']
register('alex','read') # alex ['read']
register('egon','music') # alex ['music']
4. 应用场景
- 对于大多数情况 值都一样的情况 , 需要将对应的形参定义成 默认形参
四. 关键字实参
1. 什么是关键字实参
- 在 调用函数时,按照 key=value 的形式指定的实参,称之为关键字实参
- 特点:可以打乱顺序,但仍能指名道姓地为指定形参赋值
🦢定义阶段
def foo(x,y,z):
print(x,y,z)
🦢指名道姓的传给谁, 与顺序无关
foo(y=2,x=1,z=3) # 1 2 3
foo(z=2,aaaa=1) #少了值, 没有 aaa, 报错
2. 位置实参与关键字实参可以混合使用
- 注意 : 位置实参必须放到关键字实参的前面
def foo(x,y,z):
print(x,y,z)
foo(1,y=3,z=2) # 1 2 3
foo(y=3,z=2,1) # 报错
- 注意 2 : 不能为同一个形参重复传值
def foo(x,y,z):
print(x,y,z)
foo(1,x=1,y=3,z=2) # x 重复传值, 报错
五. 可变长参数 () 与 (*)
1. 什么是可变长
- 指的是在调用函数时,传入实参个数不固定,而实参是为形参赋值的,所以, 必须有对应格式的形参来 接收溢出的实参
2. 当形参里包含 * 与 **
- *会将溢出的位置实参全部接收, 然后 保存成元组 的形式赋值给 args**(变量名, 约定俗成的都使用这个)
🦢形参中包含 "*args", 接收溢出的位置实参
def foo(x,y,z,*args):
print(x,y,z) # 1 2 3
print(args) # args=(4,5,6,7,8)foo(1,2,3,4,5,6,7,8,)
- ** 会将溢出的关键字实参全部接收, 然后 保存成字典 的形式赋值给 kwargs**
🦢形参中包含 "**kwargs", 接收溢出的关键字实参
def foo(x,y,z,**kwargs):
print(x,y,z) # 1 2 3
print(kwargs) # kwargs={'c':3,'a':1,'b':2}
foo(x=1,y=2,z=3,a=1,b=2,c=3)
3. 当实参里包含 * 与 **
- *会将紧跟其后的实参打散 成位置实参 , 注意 后跟的应该是一个可以被*for 循环循环的类型
def foo(x,y,z,*args):
print(x,y,z) # 1 2 3
print(args) # args=([4,5,6,7,8],)
foo(1,2,3,*[4,5,6,7,8]) #foo(1,2,3,4,5,6,7,8) #把 * 里面的打散
foo(1,2,3,*(4,5,6,7,8)) #foo(1,2,3,4,5,6,7,8)
foo(1,2,3,*'hello') #foo(1,2,3,'h','e','l','l','o')
# 如果是字典, 则打散后获得的是 key
错误例子
def foo(x,y,z):
print(x,y,z)
foo(*[1,2,3]) #foo(1,2,3)
foo(*[1,2,3,4]) #foo(1,2,3,4) 多了一个 报错
foo(*[1,2,]) #foo(1,2,) 少了一个 报错
- **会将紧跟其后的实参打撒 成关键字实参 , 注意 * 后跟的必须是一个 字典*
def foo(x,y,z,**kwargs):
print(x,y,z) # 1 2 3
print(kwargs) # kwargs={"a":1,"b":2}
foo(1,2,3,**{'a':1,'b':2}) #foo(1,2,3,b=2,a=1) 把 ** 里的打散
foo(1,**{'z':3,'y':2,'x':111}) #foo(1,z=3,y=2,x=111) x 重复传值, 报错
4. 组合使用
- 在形参中,* 必须放在 ** 前
- 在实参中,* 必须放在 ** 前
🦢定义一个 "index" 函数
def index(name,age,gender):
print(f'welcome {name}{age}{gender}')
🦢定义一个 "wrapper" 函数, "index" 在其内部
def wrapper(*args,**kwargs):
index(*args,**kwargs)
wrapper(1,2,3,x=1,y=2,z=3) # 报错
🔰如果 "wrapper" 像上面这样传值的话, 就会出现以下情况:
🔰"wrapper" 形参中:# args=(1,2,3),kwargs={'x':1,'y':2,'z':3}
🔰"wrapper" 内部的 "index" 实参中得到的值:#(*(1,2,3),**{'x':1,'y':2,'z':3})-->(1,2,3,z=3,y=2,x=2)
🔰如果这样写,符合了 "wrapper",但 "wrapper" 里面有一个 "index",不符合,报错
🔰在 "index" 里面会把元组和集合打散,变成 "6" 个元素,而 "index" 里面只有 "3" 个
🦢正确写法
wrapper(name='egon',age=18,gender='male')
wrapper('egon',age=18,gender='male')
wrapper('egon',18,gender='male')
wrapper('egon',18,'male') #这种写法都可以,符合 index 的语法
六. 命名关键字参数
1. 什么是命名关键字参数 fsdsdf
- 在 * 与 ** 之间定义的形参
- 特点 : 必须按照 key = value 的形式传值
🦢"a=666", "b" 这两个就是命名关键字参数
def func(x,y=1,*args,a=666,b,**kwargs):
print(x)
print(y)
print(args)
print(a)
print(b)
print(kwargs)
func(1,2,3,4,5,6,7,b=222,c=333)
正文完