函数3 参数
1 形参与实参
形参即形式参数,就是定义函数时括号中指定的参数,本质变量名
实参即实际参数,就是在调用函数时传入的参数(括号里的参数),是一个实际的值
在调用函数时就会自动把形参(变量名)和实参(值)进行绑定
在函数调用结束之后绑定关系就会接触
def func1(a,b): # a,b就是形参 a = 1,b = 2 print(a) print(b) func1(1,2) # 1,2就是实参
2 位置参数
根据调用阶段 参数分为两类 形参和实参
所以对应的 位置参数也有两种:
位置形参
位置实参
位置,其实指的是顺序,从左往右来定义的参数就是位置(顺序)参数
需要注意的是:
只要是定义了的位置形参都必须被传值
位置形参的数量与位置实参的数量必须一致,不能多传,也不能少传
实参会按照传入的位置依次赋值给形参
def func(a,b,c):# abc都是位置形参 print(a,b,c) func(2,1,3) # 1,2,3都是位置实参 def register(name,passwod,sex): print("my name is %s pwd:%s sex:%s" % (name,passwod,sex)) register("123","rose","woman")
3 关键字参数
关键字实参
在调用函数时,指名道姓的为形参赋值就称之为关键字参数
其优点是:
可以打破传入参数的顺序 可以不与形参顺序相同
注意:
1.不管以什么样的方式传值,每一个形参都必须被传值
2.关键字参数必须位于位置参数的后面
3.不能为同一个参数传多次值
4.使用关键字传参时,实参的名字必须与形参的名字匹配
到底是位置参数还是关键字参数 由实参决定
# def func(a,b,c): # print(a) # print(b) # print(c) # # # func(1,2,c = 3) # 与位置参数没区别 # # func(1,2,a = 10) # 重复为a传值了两次 # # func(c = 3,1,2) # 语法错误 关键字参数出现在了位置参数的前面 # func(a = 1,c = 3,b = 2) # 可以打破位置参数的顺序限制 def register(name,pwd): print("name is",name) print("password is",pwd) # register(pwd="123",name="bgon") register("jack",pwd="321") # 可以不用完全按照顺序来传值 # open("今日内容","r",encoding="utf-8")
4 默认形参
在定义时,就已经为形参指定了一个值,那这个形参就称之为默认形参
特点:
在调用时可以不用为默认形参传值,使用这个参数时就是默认值
当然也可以传值,这样的话内部使用就是你传入的值
场景:
当函数中的某一形参经常出现重复的值时,就可以将其定义为默认形参,
可以简化调用代码
需要注意
1.默认形参必须放在非默认形参的后面
2.默认形参的值在定义时就已经固定了
3.默认形参的默认值设置为一个不可变类型,
会导致 每次函数调用都共用同一个默认参数,我们应该将函数设计为独立的功能 每次调用互不干扰
只能是 int float str tuple
# def reg(name,age,sex="woman"): # print(name,age,sex) # # reg("rose",18) # reg("kairy",20) # reg("maria",39) # reg("lili",78) # reg("egon",38,"man") # def reg1(name,sex,hobby,li=()): # print(name,sex) # print(li) # # reg1("bgon","man","music") # reg1("cgon","man","play") # def reg1(name,sex,hobby): # print(name,sex) # print(hobby) # # reg1("bgon","man",["music","play"]) # def fun(b,c,a=10): # pass # 2. # 默认形参的值在定义时就已经固定了 # x = 1 # def func2(a,b=x): # print(a,b) # # x = 100 # 在定义时,已经把x值1赋给b了,所以后面在对x做处理不会改变b的默认值 # func2(20)
可变长参数指的是,可以传任意个数的实参
传入实参是为了给形参来使用,那就意味,必须让形参也具备可以接受任意个数的实参的能力
也就是*和**
*的使用
带*的形参
带*的形参表示可以接受任意个数的实参,接收到的实参会被打包成元组类型
形参的名字可以随意,但是建议用args 是arguments的缩写
带*的实参
在实参前面加*,会自动将*后的值,打散("abc" 打散 成了 "a","b","c")
带*的形参不能接收关键字实参
可变长形参与位置形参混合使用
1.当可变长形参出现在了位置形参的前面时,那么后面的位置形参必须以关键字实参来传入
2.当可变长形参出现在位置形参后面,会先按照顺序给前面位置形参赋值最后剩余的就赋值给可变长args
**的使用
形参中如果带有**,会把关键字实参打包成字典类型传入
只能接收多出来的关键字实参
实参中带**,会把**后的字典(也必须是字典类型)打散,成关键字实参(**{"a":1} 打散为 a = 1)
* 和 **可以为函数预留扩展空间,后期可以根据需求增加参数,而且旧的函数调用方式也不会出现问题
简单地说就是提高函数的扩展性
# def func(*args): # print(args) # pass # # func(1) # func(1,2) # func(1,2,3) # def func(a,b,c,d,e): # print(a,b,c,d,e) # # func(1,2,*[0,9,8]) # func(1,2,a,b,c) # iterable 可迭代的 只要是可以被for in 循环使用的都是可迭代 字符串 列表 元组 字典 集合 # # func(a=1) # func(a=1,b=2) # func(a=1,b=2,c=3) # 位置形参与 可变长形参混合使用 # 当可变长形参出现在了位置形参的前面时,那么后面的位置形参必须以关键字实参来传入 # def func(*args,a,b): # print(a,b,args) # # func(1,2,3,4,b=5) # 当可变长形参出现在位置形参后面,会先按照顺序给前面位置形参赋值最后剩余的就赋值给可变长args # # def func(a,b,*args): # print(a,b,args) # # func(1,2,3,4,5,) # # **不能接收位置实参 # def func(**b): # print(b) # # func(a = 100,c = "abc") # 先为前面的形参赋值,后续的多余的关键字参数赋值给** # def func(a,c,**b): # print(a,c) # print(b) # # func(1,s = 100,c = "abc") # def func(c,a=1,**b): # print(a,c) # print(b) # # func(1,2) # def func(a=1,b=2,**kwargs): # print(a,b,kwargs) # # func(a = -1,b=-2,s = 10) # 实参中带** # def func(a,b,c): # print(a,b,c) # # func(**{"a":"rose","b":"woman","c":18}) # func(name="rose",sex="woman") # # # # print(**{"name":"rose"}) # print(name="rose") # 写一个带有可变长的位置形参函数 # def func(name,pwd,**kwargs): # if name == "bgon" and pwd == "123": # if "phone" in kwargs: # if kwargs["phone"] == "110": # print("登录成功!") # else: # print("请传入手机号验证!") # else: # print("登录失败!") # # func("bgon","123") # func("bgon","123",phone = "110") # 该方式可以接受任意个数的位置实参和关键字实参, # 但要注意顺序,位置实参必须在关键字之前 def inner(name,sex,age): print(name,sex,age) def outer(*args,**kwargs): print(args) print(kwargs) inner(*args,**kwargs) # inner(1,2,3,a=10,b=20) outer(1,2,3,100,a=10,b=20) # 上述写法 可以将outer接收到的所有参数 原模原样的传给inner函数
当我们想要将传给一个函数的参数格式原方不动地转嫁给其内部的一个函数,应该使用下面这种形式
# def bar(x,y,z): # print(x,y,z) # # def wrapper(*args,**kwargs): #args=(1,2,3,4,5,6) kwargs={'a':1,'b':2,'c':3} # bar(*args,**kwargs) #bar(*(1,2,3,4,5,6),**{'a':1,'b':2,'c':3}) #这是bar() 实参中带* 和** #bar(1,2,3,4,5,6,a=1,b=2,c=3) # wrapper(1,2,3,4,5,6,a=1,b=2,c=3) # !!!!!!!!!!!!!!!当我们想要将传给一个函数的参数格式原方不动地转嫁给其内部的一个函数,应该使用下面这种形式 # def bar(x,y,z): # print(x,y,z) # # def wrapper(*args,**kwargs): #args=(1,2) kwargs={'z':3} # bar(*args,**kwargs) #bar(*(1,2),**{'z':3}) #bar(1,2,z=3) # wrapper(1,2,z=3) # 虽然调用的是wrapper,但是要遵循的确是bar的参数标准
# 五 命名关键字参数: 放到*与**之间的参数称之为命名关键字参数(了解即可) # 注意: 命名关键字参数必须按照key=value的形式传值 # def foo(x,y,*args,m,n,**kwargs): #args=(3,4,5,6,7,8) # print(x,y) # 1,2 # print(args) #(3,4,5,6,7,8) # print(m,n) #222,333 # print(kwargs) # # foo(1,2,3,4,5,6,7,8,n=333,m=222,a=1,b=2)
#当形参碰到一起后,从左向右的顺序为:
位置 >> 默认 >> *args >> 命名关键字参数 >> **kwargs # def foo(x,y=1,*args,m,**kwargs): # print(x) # print(y) # print(args) # print(m) # print(kwargs) #