🍖函数参数

一.函数参数两大类

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)
posted @ 2020-11-27 11:52  给你骨质唱疏松  阅读(256)  评论(0编辑  收藏  举报