标签:内存地址 函数定义 默认 扩展 idt name 抛出异常 inf wrap
在定义函数阶段定义的参数称之为形式参数,简称形参,相当于变量名。
在调用函数阶段传入的值称为实际参数,简称实参。相当于"变量值"的内存地址。(Ps:Python中的所有传值都是传递的内存地址,因此Python中的传值也被称为引用传值。)
1.在调用阶段,实参("变量值的内存地址引用")会绑定给形参("变量名")
2.这种绑定关系只能在函数体内使用
3.实参与形参的绑定关系在函数调用时生效,函数调用结束后解除绑定关
在函数定义阶段,按照从左到右的顺序直接定义的"变量名"被称为位置形参,它的特点是必须被传值,多一个少一个也不行。
默认参数的值是在函数定义阶段就被赋予的,准确的说是赋予形参了一个默认的值的内存地址。当调用时可以不对该形参进行传值,如不对该形参进行传值则使用默认的值,反之则使用传入的实参值,需要注意在定义时默认形参必须放在位置形参后面,否则会抛出异常。
上面一直在使用位置传参的方式,在函数调用阶段,按照从左至右的顺序依次传入值的方式被称为位置传参,特点是按照实参摆放的顺序与形参一一对应进行传值。来看一段错误示范:
在函数调用阶段,按照key=value的形式传入值的方式被称为关键字传参,可以打破顺序为形参进行传值。注意:若使用关键字传参需注意必须跟在位置传参的后面。(也是个人比较推崇的一种传值方式)。
*是一种语法,args是一种约定俗称。如果定义一个函数时不知道使用者要用位置传参的方式传入多少个实参,可使用*args来进行接收所有多余的被传入的实参,这些多余的被传入实参会被打包成元组类型。(args只是形参名,但是按照约定俗称如果要接收多个实参的形参名一般命名为args)
def func(x,y,*args): print("x -->",x) print("y -->",y) print("args -->",args) func(1,2,3,4,5,"6",[7,8,9]) # 实参 1 和 2 会根据位置传参依次被形参x,y所接收(内存地址)。剩下的所有通过位置传参的实参全部被args所接收。 # ==== 执行结果 ==== """ x --> 1 y --> 2 args --> (3, 4, 5, ‘6‘, [7, 8, 9]) """
**也是一种语法。kwargs则是**后面形参名的约定俗称。如果定义一个函数时不知道使用者要用关键字传参的方式传入多少个实参,可使用**kwargs来进行接收所有多余的被传入的实参,这些多余的被传入实参会被打包成字典类型。
def func(name,age,**kwargs): print("name -->",name) print("age -->",age) print("kwargs -->",kwargs) func("yunya",18,gender="male",height="1.92",body_weight="180Kg")
# 实参yuya,18通过位置传参会被name和age所接受(内存地址),剩下的所有关键字传参的实参全部被kwargs所接收。 # ==== 执行结果 ==== """ name --> yunya age --> 18 kwargs --> {‘gender‘: ‘male‘, ‘height‘: ‘1.92‘, ‘body_weight‘: ‘180Kg‘} """
*可以用在实参中,实参中带*,先将*后面的值(一般为容器类型,不包含字典类型)拆分为实参后再以位置传值的方式进行传入。
def func(x,y,z): print("x --->",x) print("y --->",y) print("z --->",z) func(*["a","b","c"]) # ==== 执行结果 ==== """ x ---> a y ---> b z ---> c """
**也可以用在实参中,实参中带**,先将**后面的值(必须为字典类型)拆分为key=value的形式后再以关键字传值的方式进行传入。
def func(x,y,z): print("x --->",x) print("y --->",y) print("z --->",z) func(**{"x":1,"y":2,"z":3}) # ==== 执行结果 ==== """ x ---> 1 y ---> 2 z ---> 3 """
其实关于实参传值的方式就2种,一种是位置传参,一种是关键之传参。所以一个函数如果定义了 *args 与 **kwargs 后则代表它能接收足够多的参数。需要注意的是*args必须定义在**kwargs之前,否则会抛出异常。
def wrapper(*args, **kwargs): print(args) # (1, 2, 3) print(kwargs) # {‘name‘: ‘Yunya‘, ‘age‘: 18} wrapper(1, 2, 3, name="Yunya", age=18)
我们可以指定某些形参的传值方式必须为关键字传参,这里只需要用到一个*符号即可。*前面的形参代表使用位置传参的方式接收实参(内存地址),*后面的形参代表必须使用关键字传参的方式为其形参绑定实参(内存地址),并且*后的形参可以设置默认参数。
总体来说,形参定义的顺序分别是:接收位置传值的形参,*args,带默认参数的形参,必须以命名关键字传入的形参,**kwargs。
我们看一下示例:
def register(name, age, *args, gender="male", hobby, **kwargs): print(f"{name}") # Yunya print(f"{age}") # 18 print(f"{gender}") # male print(f"{args}") # (‘a‘, ‘b‘, ‘c‘) print(f"{hobby}") # (‘篮球‘, ‘足球‘, ‘兵乓球‘) print(f"{kwargs}") # {‘other‘: ‘暂无‘} register("Yunya", 18, "a", "b", "c", hobby=("篮球", "足球", "兵乓球"), other="暂无")
这里要提前说一下,装饰器算是Python基础里比较难的一个点。它包含函数嵌套使用与*和**的多重传参,这里不说那么多。直接上个代码图,看懂了就可以关闭本页面了。
def func(x, y, z): print(x, y, z) # 1 v1 v2 def wrapper(*args, **kwargs): func(*args, **kwargs) # 实参用 * 和 ** 。拆分开, * 是位置传值,**是关键字传值. # args (1) kwargs {"y":"v1","z":"v2"} ---> func(1,y="v1",z="v2") 最终传入样式 wrapper(1, y="v1", z="v2")
再次十分感谢!!!如果您觉得我的这篇文章还不错的话请点击推荐。谢谢!!!
标签:内存地址 函数定义 默认 扩展 idt name 抛出异常 inf wrap
原文地址:https://www.cnblogs.com/Yunya-Cnblogs/p/12883117.html