010、函数、函数的参数
1、函数
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
定义一个函数
你可以定义一个由自己想要功能的函数,以下是简单的规则:
- 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
- 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
- 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
- 函数内容以冒号 : 起始,并且缩进。
- return [表达式] 结束函数,选择性地返回一个值给调用方,不带表达式return的, 相当于 return None。只有return语句的函数,实际等同于return None 。
break 与 return 区别:break 跳出for while循环, return 退出函数 ;
函数返回多个值时,返回的是元组;示例代码如下:
def height_weight(name, height, weight): return height, weight # 实际返回的是一个元组 print(height_weight('sky', 175, 65))
执行结果如下:
D:\SkyWorkSpace\WorkSpace\Pytest\Temp\day06\venv\Scripts\python.exe D:/SkyWorkSpace/WorkSpace/Pytest/Temp/day06/gggg/demo_04.py (175, 65) Process finished with exit code 0
参数
以下是调用函数时可使用的正式参数类型:
- 位置参数
- 关键字参数
- 默认参数 ,形参=实参
- 不定长参数 *args **kwargs
- 参数顺序:位置参数 > 默认参数 > 不定长参数
位置参数(必传参数)
必需参数须以 正确、唯一对应的顺序 传入函数。调用时的数量必须和声明时的一样。
位置参数,即传入函数的实际参数必须与形式参数的数量和位置对应 。
示例代码如下:
def show_info(name, age, height): print('我的名字是:{0},我的年龄是:{1},我的身高是:{2}'.format(name, age, height)) # show_info() # 需传入3个参数,否则报错:TypeError: show_info() missing 3 required positional arguments: 'name', 'age', and 'height' show_info('sky', 25) # 只传入了2个参数,会报错: TypeError: show_info() missing 1 required positional argument: 'height' show_info('sky', 25, 175)
执行结果如下:
def show_info(name, age, height): print('我的名字是:{0},我的年龄是:{1},我的身高是:{2}'.format(name, age, height)) # show_info() # 需传入3个参数,否则报错:TypeError: show_info() missing 3 required positional arguments: 'name', 'age', and 'height' # show_info('sky', 25) # 只传入了2个参数,会报错: TypeError: show_info() missing 1 required positional argument: 'height' show_info('sky', 25, 175)
关键字参数
关键字参数和函数调用关系紧密( 函数调用时,产生关键字参数的说法。),函数调用使用关键字参数来确定传入的参数值;
关键字参数是指使用形式参数的名字来确定输入的参数值。通过此方式指定函数实参时,不再需要与形参的位置完全一致,只要将参数名写正确即可;
使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值;
使用 位置参数 和 关键字参数 混合传参的方式,需要注意:混合传参时关键字参数必须位于所有的位置参数之后。
示例代码如下:
# 函数定义时,默认参数需放在位置参数后面 def show_info(name, age, height=170): print('我的名字是:{0},我的年龄是:{1},我的身高是:{2}'.format(name, age, height)) show_info('sky', 25) show_info('sky', 25, 175) show_info('sky', 25, height=175) # show_info('sky', age=25, 175) # 混合传参时关键字参数必须位于所有的位置参数之后。 # 否则报错:SyntaxError: positional argument follows keyword argument show_info(name='sky', age=25, height=175)
执行结果如下:
D:\SkyWorkSpace\WorkSpace\Pytest\Temp\day06\venv\Scripts\python.exe D:/SkyWorkSpace/WorkSpace/Pytest/Temp/day06/gggg/demo_01.py 我的名字是:sky,我的年龄是:25,我的身高是:170 我的名字是:sky,我的年龄是:25,我的身高是:175 我的名字是:sky,我的年龄是:25,我的身高是:175 我的名字是:sky,我的年龄是:25,我的身高是:175 Process finished with exit code 0
默认参数
调用函数时,如果没有传递参数,则会使用默认参数;
函数定义时,默认参数 需放在 非默认参数 后面;
示例代码如下:
# 函数定义时,默认参数需放在非默认参数后面 def show_info(name, age=25, height=170): print('我的名字是:{0},我的年龄是:{1},我的身高是:{2}'.format(name, age, height)) show_info('sky', 25) # 函数调用了默认参数 height=170 show_info('sky', 180) # 有两个默认参数时,只传一个默认参数,实际传的时第一个参数 ; show_info('sky', 25, 175)
执行结果如下:
D:\SkyWorkSpace\WorkSpace\Pytest\Temp\day06\venv\Scripts\python.exe D:/SkyWorkSpace/WorkSpace/Pytest/Temp/day06/gggg/demo_01.py 我的名字是:sky,我的年龄是:25,我的身高是:170 我的名字是:sky,我的年龄是:180,我的身高是:170 我的名字是:sky,我的年龄是:25,我的身高是:175 Process finished with exit code 0
不定长参数 (*args **kwargs )
args 是 arguments 的缩写,表示位置参数;kwargs 是 keyword arguments 的缩写,表示关键字参数 ;
你可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,和上述 3 种参数不同,声明时不会命名。基本语法如下:
加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。
如果在函数调用时没有指定参数,它就是一个空元组。我们也可以不向函数传递未命名的变量。
加了两个星号 ** 的参数会以字典的形式导入。
def print(self, *args, sep=' ', end='\n', file=None) 一般的顺序都是:位置参数,*args ,默认参数, 左边是print内置函数;
两个参数一起出现时,*args一定要出现在**kwargs前面; def quit(*args, **kwargs): 这种有 *args, **kwargs 的叫做万能参数 ;
通过一个函数调用来理解 ' * ' 的作用:
函数调用时,fun(*b) 解包 : 示例代码如下:
def fun(a, b, c): print(a, b, c) fun(1, 2, 3) # 传递位置参数 b = [4, 5, 6] # unpack传递3个参数 fun(*b) # c = [7, 8, 9, 10] # 多一个参数,报错; # fun(*c) # 报错:TypeError: fun() takes 3 positional arguments but 4 were given; # d = [10, 11] # 少一个参数,报错; # fun(*d) # 报错: TypeError: fun() missing 1 required positional argument: 'c'; # ‘*e’ 与 位置参数 混合使用 e = [12, 13] fun(14, *e)
执行结果如下:
D:\SkyWorkSpace\WorkSpace\Pytest\Temp\day06\venv\Scripts\python.exe D:/SkyWorkSpace/WorkSpace/Pytest/Temp/day06/test_demo/test_06.py 1 2 3 4 5 6 14 12 13 Process finished with exit code 0
通过一个函数的定义来理解 ' *args ' 的含义
函数定义时,fun(*args) 打包 ;
‘*args’在函数定义中是做什么用的?它接收元组作为位置参数,而非是常见的参数列表。在这里,”args”是个元组。调用函数打印”args”时,他会打印元组中包含的所有数值。
示例代码如下:
def fun(*args): print(args) # 传一个位置参数调用此函数 fun(13) # 传多个参数调用此函数 fun(11, 93, 43) print('=======fun_1=========') # ”*args”与”常规参数列表”混合使用 # 在这个函数定义中,参数”a”代表”常规参数列表”。 def fun_1(a, *args): print("a is ", a) print("args is ", args) # 传四个位置参数调用此函数: # ’a’打印出为11,即第一个位置参数。’a’之后只一个参数’*args’. # 因此,’args’接收除常规参数之外的位置参数作为元组。因此元组args作为元组接收12,34和43。 fun_1(11, 12, 34, 43) # 我们也可以传一个位置参数来调用此函数: # 我们传的唯一一个参数分配给了常规参数’a’.因此,’args’接收到一个空元组。 fun_1(91) print('=======fun_2=========') # 既然我们获取了”args”,我们可以提取需要的数值来做我们想做的事情。重新定义”fun”: # ‘args’既然是元组,我们就可以遍历它。 def fun_2(a, *args): print(a) print("args can receive a tuple of any number of arguments, let's print all that.") for arg in args: print(arg) # 现在我们传任意个参数来调用此函数: fun_2(1, 5, 6, 7)
执行结果如下:
D:\SkyWorkSpace\WorkSpace\Pytest\Temp\day06\venv\Scripts\python.exe D:/SkyWorkSpace/WorkSpace/Pytest/Temp/day06/test_demo/test_06.py (13,) (11, 93, 43) =======fun_1========= a is 11 args is (12, 34, 43) a is 91 args is () =======fun_2========= 1 args can receive a tuple of any number of arguments, let's print all that. 5 6 7 Process finished with exit code 0
通过一个函数的调用来理解 ' ** ' 的作用
函数调用时,fun(**b) 解包 : 示例代码如下:
# 定义一个三个参数的函数,并用多种方式调用: def fun(a, b, c): print(a, b, c) fun(1, 5, 7) # 传递位置参数 fun(a=1, b=5, c=7) # 关键字传值 # 使用”**”调用函数,这种方式我们需要一个字典.注意:在函数调用中使用”*”, # 我们需要元组;在函数调用中使用”**”,我们需要一个字典 d = {'b': 5, 'c': 7} # unpack传递3个参 fun(1, **d)
执行结果如下:
D:\SkyWorkSpace\WorkSpace\Pytest\Temp\day06\venv\Scripts\python.exe D:/SkyWorkSpace/WorkSpace/Pytest/Temp/day06/gggg/demo_04.py 1 5 7 1 5 7 1 5 7 Process finished with exit code 0
在函数调用中 ”**” 做了什么?
它 unpack 字典,并将字典中的数据项作为键值参数传给函数。因此, ”fun(1, **d)”的写法与”fun(1, b=5, c=7)”等效.
为了更好的理解再多举几个例子:
>>> d = {'c':3} >>> fun(1, 4, **d) 1 4 3 >>> d = {'a':7, 'b':3, 'c':8} >>> fun(**d) 7 3 8
让我们制造一些错误:
>>> d = {'a':7, 'b':3, 'c':8, 'd':90} >>> fun(**d) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: fun() got an unexpected keyword argument 'd'
这次调用等同于’fun(a=7, b=3, c=8, d=90)’,但函数只需要三个参数,因此我们得到TypeError
>>> d = {'a':7, 'b':3,'d':90} >>> fun(**d) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: fun() got an unexpected keyword argument 'd'
fun(**d)等同于fun(a=7, b=3, d=90).传给函数”fun”想要的参数个数,但参数列表中并没有’d’,调用中’d’键值参数传给函数导致TypeError.
通过函数定义来理解 ’**kwargs’ 的含义
重定义函数”fun”:
>>> def fun(a, **kwargs): ... print a, kwargs ...
此函数只用一个位置参数,因为常规参数列表中只有一个变量’a’.但是通过”**kwargs”,可以传多个键值参数。
>>> fun(1, b=4, c=5) 1 {'c': 5, 'b': 4} >>> fun(45, b=6, c=7, d=8) 45 {'c': 7, 'b': 6, 'd': 8}
在函数定义中”**kwargs”意味着什么?
用”**kwargs”定义函数,kwargs接收除常规参数列表职位的键值参数字典。在这里’kwargs’是个字典。
重新定义函数:
>>> def fun(a, **kwargs): ... print "a is ", a ... print "We expect kwargs 'b' and 'c' in this function" ... print "b is ", kwargs['b'] ... print "c is ", kwargs['c'] ... >>> fun(1, b=3,c=5) a is 1 We expect kwargs 'b' and 'c' in this function b is 3 c is 5
错误调用:
>>> fun(1, b=3, d=5) a is 1 We expect kwargs 'b' and 'c' in this function b is 3 c is Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 5, in fun KeyError: 'c'
上面的调用,位置参数’a’和键值参数’b’都打印出来了。传入的其他键值参数是’d’,函数需要键值参数’c’,并从字典’kwargs’获取。但没有传入键值’c’,引发KeyError.如果传入了键值’c’就不会引发这个错误
>>> fun(1, b=3, d=5, c=9) a is 1 We expect kwargs 'b' and 'c' in this function b is 3 c is 9
由于’**kwargs’在函数参数列表中,我们可以传任意个键值参数。上面的调用传入了”d”,但函数并没用到。
另外一个错误:
>>> fun(1, {'b':2, 'c':34}) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: fun() takes exactly 1 argument (2 given)
正如错误提示,函数’fun’只需要一个位置参数,却给了两个。尽管’kwargs’接收键值参数作为一个字典,但你不能传一个字典作为位置参数给’kwargs’.你可以像下面那样调用:
>>> fun(1, **{'b':2, 'c':34}) a is 1 We expect kwargs 'b' and 'c' in this function b is 2 c is 34
在一个字典前使用”**”可以unpack字典,传字典中的数据项作为键值参数。
最后看一个简单的例子:
# 1、函数调用时, fun(*参数) unpack包 # 2、函数定义时, fun(*args) 打包 # 3、函数调用时, fun(**参数) unpack包 # 4、函数定义时, fun(**kwargs) 打包 print('=======1、函数调用时, fun(*参数) unpack包======') def fun(a, b, c): print(a, b, c) d = (1, 2, 3) e = [4, 5, 6] fun(*d) fun(*e) print('=======2、函数定义时, fun(*args) 打包======') def fun_1(*args): print(args) fun_1(1, 2, 3) print('=======3、函数调用时, fun(**参数) unpack包======') def fun_2(f, g, h): print(f, g, h) i = {'f': 7, 'g': 8, 'h': 9} # key名要和函数形参名一样,否则报错 fun_2(**i) print('=======4、函数定义时, fun(**kwargs) 打包======') def fun_3(**kwargs): print(kwargs) fun_3(a=1, b=2, c=3)
执行结果如下:
D:\SkyWorkSpace\WorkSpace\Pytest\Temp\day06\venv\Scripts\python.exe D:/SkyWorkSpace/WorkSpace/Pytest/Temp/day06/gggg/demo_04.py =======1、函数调用时, fun(*参数) unpack包====== 1 2 3 4 5 6 =======2、函数定义时, fun(*args) 打包====== (1, 2, 3) =======3、函数调用时, fun(**参数) unpack包====== 7 8 9 =======4、函数定义时, fun(**kwargs) 打包====== {'a': 1, 'b': 2, 'c': 3} Process finished with exit code 0
参考资料:https://www.runoob.com/python3/python3-function.html
https://www.cnblogs.com/cwind/p/8996000.html