25 函数参数

211次阅读
没有评论

共计 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)
正文完
 
shawn
版权声明:本站原创文章,由 shawn 2023-06-16发表,共计3942字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)