笔者:风起怨江南 出处:https://blog.csdn.net/JackMengJin 笔者原创,文章欢迎转载,如果喜欢请点赞+关注,感谢支持!
本篇主要讲解Python函数参数的重要知识点,上一篇中涉及到函数的定义等相关知识点,回顾请点链接->传送门。
目录
函数参数的定义和用法
函数参数前先回顾下函数的定义和调用。
一、函数定义
1.1 什么是函数
上一篇内容讲到了函数的概念:
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。更直白的话说就是:函数是当输入一定的数据以后,
能根据里面的执行步骤,可以算出另一些数据的值。同时可以得到数据,获取输出值。
那么其实调用或自定义足够多的函数后,会对函数有更深刻的理解:
函数就是存储指定的程序(代码),或者把函数看成一个盒子,外面的代码是另一个盒子,相互之间没有关系。Python框架的源码都是基于函数。
1.2 函数的表示
换而言之,函数就是一个一段程序,一段代码,我们需要用函数去达到所期望的效果,所以将代码封装为函数,从而可以重复的去使用。
函数的表示:
def add(a,b):
'''这是文档字符串,告诉函数干嘛用的'''
#函数体
c = a + b
return c
def 顶行写, 加定义的函数名(括号里要传的参数)冒号结尾:
'''空4格,这里要写函数的文档字符串,用来描述函数的作用'''
这里是代码块,也就是函数体。
return 返回一个值。
1.3 函数的调用
函数调用的概念:函数调用就会执行函数内部的逻辑。
先定义一个作用为计算器的函数,传入两个参数并计算:
def calculator(num1,num2):
'''文档字符串
函数的作用:该函数通过输入两个参数,并根据输入的数字:1表示加、2表示减、3表示乘、4表示除,来计算求结果
返回值:操作后的值
'''
#while循环判断输入的数字是否为1-4,如果不是,重新输入
while True:
sign = input('请输入数字(1表示加、2表示减、3表示乘、4表示除):')
if sign == '1' or sign == '2' or sign == '3' or sign == '4':
break
else:
print('输入操作错误,请输入数字1-4。')
#定义变量num_sum为计算结果,先赋值0
num_sum = 0
if sign == '1': #当输入数字为1时,相加
num_sum = num1 + num2
elif sign == '2': #当输入数字为2时,相减
num_sum = num1 - num2
elif sign == '3': #当输入数字为3时,相乘
num_sum = num1 * num2
else: #当输入数字为4时,相除,同时判断如果被除数为0时,退出计算
if num2 == 0:
return print('被除数不能为0,退出计算,返回None!')
num_sum = num1 / num2
return num_sum
自定义完calculator()函数之后如何去验证和调用这个函数呢?
#输入的值转换为浮点类型
num1 = float(input('请输入第一个需要计算的数字:'))
num2 = float(input('请输入第二个需要计算的数字:'))
#声明变量,用来存储函数计算的值,并打印
num_sum = calculator(num1,num2)
print('经过计算,最后的结果为:',num_sum)
运行后的结果:
请输入第一个需要计算的数字:100
请输入第二个需要计算的数字:25
请输入数字(1表示加、2表示减、3表示乘、4表示除):4
经过计算,最后的结果为: 4.0
可以看到,在函数中传入两个参数(也就是两个变量),通过运算后,返回出一个值,再通过print打印将返回的值打印出来。
所以函数的调用方法:
函数名(参数)
在定义完函数后,直接用函数名加里面的参数内容,就可以直接去调用这个函数。
关于函数的参数部分在第二节具体讲解。
函数里调用函数?
在一个函数里调用另一个函数,函数调用就会执行函数内部的逻辑。当内部逻辑里调用另一个函数时,再在去读调用的那个函数里内部的逻辑。
举个简单的例子:
#定义一个函数,用于比较传入数值的大小,返回值为比较大的数
def compareNum(num1,num2):
'''比较大小,返回较大值'''
max_num = max(num1,num2)
return max_num
#定义另一个函数,根据传入的两个数值,选出最大的一个数值,并打印出相应行数的hello world
def powerNum(num1,num2):
'''传入的两个数值,选出最大的一个数值,并打印出相应行数的hello world'''
max_num = compareNum(num1,num2)
for i in range(max_num):
print('hello world!')
可以看到第二个函数中调用了第一个函数,那么传入两个变量。运行下会有什么效果:
num1 = int(input('数字1:'))
num2 = int(input('数字2:'))
powerNum(num1,num2)
数字1:2
数字2:5
hello world!
hello world!
hello world!
hello world!
hello world!
这里函数调用函数有什么需要注意的地方?如果将上面的两个函数位置调换一下,会报错么?
#定义另一个函数,根据传入的两个数值,选出最大的一个数值,并打印出相应行数的hello world
def powerNum(num1,num2):
'''传入的两个数值,选出最大的一个数值,并打印出相应行数的hello world'''
max_num = compareNum(num1,num2)
for i in range(max_num):
print('hello world!')
#定义一个函数,用于比较传入数值的大小,返回值为比较大的数
def compareNum(num1,num2):
'''比较大小,返回较大值'''
max_num = max(num1,num2)
return max_num
num1 = int(input('数字1:'))
num2 = int(input('数字2:'))
powerNum(num1,num2)
数字1:1
数字2:2
hello world!
hello world!
很显然没有报错,这是跟python的运行机制有关,下面具体分析一下错误情况。
错误的调用顺序:
#定义另一个函数,根据传入的两个数值,选出最大的一个数值,并打印出相应行数的hello world
def powerNum(num1,num2):
'''传入的两个数值,选出最大的一个数值,并打印出相应行数的hello world'''
max_num = compareNum(num1,num2)
for i in range(max_num):
print('hello world!')
num1 = int(input('数字1:'))
num2 = int(input('数字2:'))
powerNum(num1,num2)
#定义一个函数,用于比较传入数值的大小,返回值为比较大的数
def compareNum(num1,num2):
'''比较大小,返回较大值'''
max_num = max(num1,num2)
return max_num
我将调用函数的位置放在了函数的前面,运行会怎样呢?
数字1:1
数字2:2
Traceback (most recent call last):
File "E:/MyLife/网课学习/柠檬班/作业/博客/demo_new.py", line 19, in <module>
powerNum(num1,num2)
File "E:/MyLife/网课学习/柠檬班/作业/博客/demo_new.py", line 13, in powerNum
max_num = compareNum(num1,num2)
NameError: name 'compareNum' is not defined
果不其然报错了,NameError: name 'compareNum' is not defined,原因是为什么?
其实原因还是和python的运行机制有关,python在运行的时候,先去根据顺序去执行每一条顶行写的代码,当执行到powerNum(num1,num2)调用函数这一行时,进入到powerNum函数体的内部,再去调用里面的函数compareNum函数。此时python会发现,咦?怎么没有 compareNum这个函数呢?所以便没有继续去执行下面的代码,而是直接报错,停止运行。
总结:函数调用函数的时候,一定要注意先后顺序,可以用打断点和debug的方法去一行一行理解。
二、函数参数的定义
讲函数参数定义前,先思考一个问题,为什么要给函数加参数?这里先卖个关子,等了解所有函数参数的定义后自然而然就明白了。函数的参数有哪些呢?
2.1 形式参数
形式参数是在函数定义的时候,函数名括号里的内容,可以理解为是变量名。
比如上面例子中自定义的函数:
def compareNum(num1,num2):
这里的num1和num2就是形式参数,简称形参。
2.2 实际参数
实际参数就是函数调用的时候函数名括号里的内容。
num1 = int(input('数字1:'))
num2 = int(input('数字2:'))
powerNum(num1,num2)
由于已经的值函数的目的是为了存储程序,而且变量都是会变的量,所以在定义函数的时候,变量一般放在外面,在调用
的时候在将变量传入到函数中,所以这里的变量也就是说所的实际参数。
这里的num1和num2,就是实际参数,简称为实参。
2.3 位置参数
理解了形式参数和实际参数的含义,再去理解位置参数(positional argument)就比较简单了。
位置参数其实就是表示形式参数和实际参数之间的关系,要按顺序对应。这里需要注意的是,所谓的对应指的是一一对
应,不能多不能少,顺序也要刚刚好。
def compareNum(num1,num2):
'''比较大小,返回较大值'''
max_num = max(num1,num2)
return max_num
compareNum(1,2,3)
如果实际参数和形式参数有差别,就会报错:
compareNum(1,2,3)
TypeError: compareNum() takes 2 positional arguments but 3 were given
2.4 关键字参数
关键字参数(keyword argument)比较好理解了,先看例子:
def get_name(firstname,middle,lastname):
'''返回名字'''
return firstname + middle + lastname
print(get_name('罗',middle='志',lastname='翔'))
罗志翔
这里可以看到关键字参数其实就是在实际参数前面加上形式参数。如果没有关键字参数,容易搞混位置,不容易弄清每个形式
参数的意思。而加了关键字参数后,可以提高函数调用的可读性,也更加容易理解实际参数的意义。
那么关键字到底怎么来的?
而关键字必须要在形式函数里选,而关键字的名字就是形式参数。
关键字参数和位置参数的区别:相对于位置参数来讲,对于参数比较多的情况下,使用关键字参数就不需要去比较了,直接就知
道表示什么意思。
同时关键字参数区别位置参数的地方:可以不按照顺序进行调用,可以交换顺序。
def get_name(firstname,middle,lastname):
'''返回名字'''
return firstname + middle + lastname
print(get_name('罗',lastname='翔',middle='志'))
罗志翔
到这里有没有发现,关键字参数特别像字典吧?只需要确定形式参数(key),位置不管怎么改变(字典是无序的)都不影响最
后的结果(键值对)。
关键字函数的优点:
- 可读性
- 不按照顺序,可以不按照套路出牌
需要注意的地方——位置:
def get_name(firstname,middle,lastname):
'''返回名字'''
return firstname + middle + lastname
print(get_name(lastname='翔','罗',middle='志'))
print(get_name(lastname='翔','罗',middle='志'))
^
SyntaxError: positional argument follows keyword argument
如果将关键字参数放在位置参数的前面,会报错!SyntaxError: positional argument follows keyword argument
关键字参数要放到位置参数后面。
关键字参数作用:可以交换参数的顺序,并且提高可读性难度内容
2.4 默认参数
默认参数的定义:默认参数就是在在函数定义的时候,给参数一个缺省值。
默认参数的表示:
def get_name(firstname,middle='志',lastname='翔'):
'''返回名字'''
return firstname + middle + lastname
print(get_name('罗','志','翔'))
罗志翔
如果没有传入该参数的实际参数时:
def get_name(firstname,middle='志',lastname='翔'):
'''返回名字'''
return firstname + middle + lastname
print(get_name('罗'))
罗志翔
这里看到返回的是缺省值,也就是默认参数。
默认参数的概念:
- 当在函数调用的时候,没有传入该参数的实际参数时,则直接使用缺省值
- 如果调用函数的时候,传入了这个实际参数,则默认值不会生效
def get_name(firstname,middle='志',lastname='翔'):
'''返回名字'''
return firstname + middle + lastname
print(get_name('罗','小','猪'))
罗小猪
默认参数的优点不难得出:
- 可以简化函数调用的过程,只需要传入少量的参数就可以实现调用过程。
这里引申一下print()这个内置函数:
为什么每次print的时候都是下一行开始的?就是因为print函数有默认参数,所以缺省状态下就是换行。
end='\n'
默认参数的位置:
其实还是位置问题,位置参数必须放在前面,默认参数需要放在位置参数的后面!
默认参数的总结:
- 默认参数值在函数定义的时候,给参数一个缺省值。
- 当在函数调用的时候,没有传入该参数的实际参数时,则直接使用缺省值。
- 如果调用函数的时候,传入了这个实际参数,则默认值不会生效。
- 好处是可以简化函数调用的过程,只需要传入少量的参数就可以实现调用过程。
2.5不定长参数——位置不定长参数
可变长参数有两种形式*args和**kwargs。
可变长参数的定义:直译的意思就是可变长参数的定义,也就是传入的实际参数是可变长度。*表示位置不定长参数,**表示关键字不定长参数(keyword args )。
- 一个*表示位置不定长参数,通常是*args表示,但起什么名字都是可以的。
- 另一个**表示关键字不定长参数,通常用**kwargs表示。
def get_name(*name):
'''打印名字'''
print(name)
get_name('罗','小','猪')
('罗', '小', '猪')
可以看到位置不定长参数打印出来是个元组类型。
虽然位置不定长参数也是位置参数,但位置参数是要在*位置参数前面的,这其实挺好去理解的:如果不定长参数在前面,位置
参数在后面,那么实际参数无论是什么,都表示的是不定长参数,而后面的位置参数永远也传不了参数。
那么可不可以有两个位置不定长参数?
不可以:
def get_name(*name,*name1):
^
SyntaxError: invalid syntax
所以在一个函数里只能有一个位置不定长参数,同样也只能有一个关键字不定长参数。
2.6不定长参数——关键字不定长参数
关键字不定长参数其实就是在变量前打**号,通常用**kwargs表示。
def get_name(*names,**kewargs):
print(names)
print(kewargs)
get_name('罗','小','猪')
('罗', '小', '猪')
{}
通过打印可以看到关键字不定长参数是字典数据类型。
所以得到一个概念:位置不定长参数和关键字不定长参数在函数里分别是用元组和字典去表示。
def get_name(**kewargs):
print(kewargs)
get_name(middle = '志')
{'middle': '罗'}
这里的关键字是在在形式参数里找,结果发现形式参数里没有middle这个参数,由于找不到,就会将middle存到key里。
不定长参数总结:
位置不定长参数有顺序的要求,是一一对应的,获取*args得到的是元组。
关键字参数可以打乱参数,但需要加个key ,获取**kwargs到的是字典。
需要注意位置:关键字参数是不能放在位置参数前面!
位置参数 > *位置参数 > **关键字参数。
2.6 函数参数意义
通过上面的内容,可以发现函数的目的就是为了存储程序。
函数用来存储程序,就是为了一遍一遍的重复去使用。也就是说所的实际参数, 实际参数就是变量。所以要把数据都提取出
来,作为变量放在参数里面。之所以不把变量放在函数里面,是因为函数一般不存储数据,函数只存储程序!
当有变量发生变化时,函数里的内容也会发生变化。把变量提取出来,作为一个形式参数,放在函数参数里去,这就是函数参数
的意义。
下一篇内容为函数的返回值和函数的作用域,敬请期待。
以上是《Python学习11:函数参数的定义和用法》的所有内容,更多python学习请继续关注我的博客——风起怨江南(传送
门),不定期更新,原创不易,如果喜欢请点赞和关注,谢谢大家的支持!
想获得免费的学习资料请添加微信公众号——风起怨江南,非常感谢大家的关注和支持!