11、Python之函数参数

Python函数 / 2020-11-06

1、什么是形式参数和实际参数?

1.1、什么是形式参数?

在定义函数阶段定义的参数可以称之为形式参数,简称形参!它定义方式类似变量名,或者说它其实就是一种变量名!

如下所示,name和age就是函数print_str定义的形式参数!

>>> def print_str(name,age):
...     print(name,age)
1.2、什么是实际参数?

在调用函数阶段传入的值可以称之为实际参数,简称实参!我们可以视之为变量值!

如下所示,sanxi和18就是实际参数,分别绑定至name和age!

>>> print_str('sanxi',18)
sanxi 18
1.3、二者有何关联?

在调用函数的阶段,实际参数的值也就是内存地址会绑定给形式参数,这种绑定关系仅在调用函数时在函数体内生效,调用结束后,自动解除绑定关系!就好比一段恋情同居关系仅在恋爱期间生效;当这段感情结束后,二人大路朝东,从此各奔东西,再无瓜葛!

2、为何要有它们?

如果没有参数,函数只有单一的被写死的功能,跟一块铁矿石在普通人手里永远都只能是块石头一样!有了参数,才赋予了函数无限的可能性!这块函数矿石通过加入不同的物质参数,从而被处理提炼成钢铁、合金等等!这就是参数的意义所在!

3、如何使用它们?

它来了!它来了!它带着位置参数它们来了!

3.1、位置参数

其实位置参数就有点类似列表,从左到右的顺序依次定义,这样的参数我们称之为位置参数!上面有形参和实参,那么位置参数当然也分位置形参和位置实参!

3.1.1、位置形参

在函数定义阶段按照从左到右的顺序直接定义的“变量名”!它的特点是:必须被传值,而且多一个不行少一个也不行!

还是以上面的为例子,我定义了两个形参:name和age,当我调用时只传递了一个实参,那就会报错!

>>> print_str('sanxi')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: print_str() missing 1 required positional argument: 'age'
3.1.2、位置实参

在函数调用阶段按照从左到右的顺序依次传入的实参,称之为位置实参,例子其实就跟上面的一模一样,就不重复展示了!

3.2、关键字参数
3.2.1、何为关键字参数?

在函数调用的阶段按照K/V形式传入的值,我们称之为关键字参数,也就是关键字实参!K/v即key/value!

3.2.2、为何要有关键字参数?

看看上面的位置参数,定死了实参只能按照从左到右的顺序传递值,这样就显得不够灵活了!这才有了关键字参数突破位置限制,就好像列表跟字典一样!一个是循序渐进的门派侠客,一板一眼苦练武功一路从弟子升至长老、掌门而不可逾越;而关键字实参则是散仙般,快意江湖,仗剑高歌,不拘泥于一招一式一草一木!

3.2.3、如何使用关键字参数?

如下所示,它突破了位置参数从左到右传递的限制!

>>> def print_str(name,age):
...     print(name,age)

>>> print_str(age=18,name='jianghu')
jianghu 18
3.3、珠璧联合混用形关

既然同为参数,那么位置参数、关键字参数也是可以混用的!只是位置参数(位置实参)必须放在关键字实参前,也不能为同一个形参重复传值!这有点像当年国共合作抗日,国军是位置参数正面牵制日军主力,共军关键字实参后方打游击战,逐步瓦解日军!当其中一方占领一方山头时,合作方不再争夺抢占!

>>> def print_str(name,age,work):
...     print(name,age,work)
...
>>> print_str('sanxi',work='ops',age=18)
sanxi 18 ops
3.4、默认参数

在定义函数阶段,就已经被赋值的形参,称之为默认参数;既然是在定义阶段就已经被赋值,就意味着调用阶段可以不用为其赋值,这比较适合重复的参数!譬如一个函数的功能为打印一个班级的学生信息,假设全是男的,那么性别这里就不必要每次传来一个“性别:男”的实参了,直接在定义阶段定义死了“性别:男”,后面就不用传了!

>>> def class_info(name,age,gender='male'):
...     print(name,age,gender)
...
>>> class_info('sanxi',18)
sanxi 18 male
# 如果确实有需要改变,直接传值就行,不需要过多操作
>>> class_info('kristal',18,'female')
kristal 18 female
3.5、位置形参与默认形参混用:

混用时,位置形参必须在默认形参的左边;默认参数的值是在函数定义阶段被赋值的,与变量一样被赋予的是值的内存地址;虽然默认参数的值可以被指定为任意数据类型,但是不推荐使用可变类型,因为你也保不准你写的程序在定义完函数后,是否有一行代码会改动这个可变数据类型,这样的话结果已经不受控制了,你也不知道会变成什么东西!

>>> wm=['male',]
>>> def class_info(name,age,gender=wm):
...     print(name,age,gender)
...
>>> wm[0]='alien'
>>> class_info('gaga',66)
gaga 66 ['alien']
# 好好一个人,就被写成外星人了,天理何在!

因此,我们应该规范自己的行为,不应该在函数里使用可变数据类型作为形式参数!保证函数调用只跟函数本身代码有关系,而不受外界代码影响!

3.6、可变长度参数('*'星号与'**'双星号)

可变长度参数指的是在调用函数时,传入的值(实参)的个数如果不固定,有可能传多了;而实参是用来为形参赋值的,所以对应着,针对溢出(多出的)的实参必须有对应的形参来接收!

3.6.1、可变长度的位置形参:

星号形参接收溢出的位置实参,溢出的位置实参会被星号保存成元祖的格式然后赋值给星号后面的形参,这个参数命名是可以随意命名的,但我们规范是星号跟args,这样可以见名知意!

如下所示,一个求总和运算中就可以用得上它了!

# 把溢出的位置实参保存成元祖格式
>>> def num(*args):
...     print(args)
...
>>> num(22,33,44)
(22, 33, 44)

# 来个求和示例
>>> def num(*args):
...     sum = 0
...     for number in args:
...             sum += number
...     print(sum)
...
>>> num(33,44,55,66,77,88,99)
462
3.6.2、可变长度的位置实参

星号也可以用在实参中,它是将星号后面的容器类型的值切割成位置参数,感觉有点那什么,因为你得记住位置参数是不能多也不能少的!

>>> def class_info(name,age,gender):
...     print(name,age,gender)
...
>>> class_info(*['sanxi',18,'male'])
sanxi 18 male
3.6.3、可变长度的关键字参数

用**两个星号,会将溢出的关键字实参保存成字典格式,然后赋值给紧跟其后的新参名,新参数可以是任意名字,但是约定俗成应该是kwargs!

>>> def class_info(name,age,**kwargs):
...     print(name,age,kwargs)
...
>>> class_info(age=18,name='sanxi',gender='male',money='None')
sanxi 18 {'gender': 'male', 'money': 'None'}
3.6.4、混用可变长度参数

混用可变长度需要注意的是args必须在kwargs之前

>>> def class_info(name,age,*args,**kwargs):
...     print(name,age,args,kwargs)
...
>>> class_info('sanxi','20',666,gender='male',money='None')
sanxi 20 (666,) {'gender': 'male', 'money': 'None'}

形参与实参混用星星

>>> number=[233,567,688]
>>> def money(name,gender,*args):
...     print(name,gender,args)
...
>>> money('sanxi','male',*number,)
sanxi male (233, 567, 688)
3.7、命名关键字参数
3.7.1、什么是命名关键字参数?

在定义函数阶段,*星号后定义的参数,就是命名关键字参数!它有个特点:必须按照关键字参数格式来传值!

3.7.2、为何要用它?

用的不多,了解即可!

3.7.3、如何使用它?

*后面跟参数即可!如下所示,当你还把他们当成是位置参数来传递实参时,就会报错说位置参数给太多了!

>>> def print_str(name,*,address,age):
...     print(name,address,age)
...
>>> print_str('andy','guangzhou','21')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: print_str() takes 1 positional argument but 3 were given

正确操作如下:

>>> print_str('andy',age=21,address='GZ')
andy GZ 21
世间微尘里 独爱茶酒中