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))
View Code

  执行结果如下:

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
View Code

 

  参数

  以下是调用函数时可使用的正式参数类型:

  • 位置参数
  • 关键字参数
  • 默认参数 ,形参=实参
  • 不定长参数  *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)
View Code

  执行结果如下:

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)
View Code

 

  关键字参数

  关键字参数和函数调用关系紧密( 函数调用时,产生关键字参数的说法。),函数调用使用关键字参数来确定传入的参数值;

  关键字参数是指使用形式参数的名字来确定输入的参数值。通过此方式指定函数实参时,不再需要与形参的位置完全一致,只要将参数名写正确即可;

  使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 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)
View Code

  执行结果如下:

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
View Code

   

  默认参数

  调用函数时,如果没有传递参数,则会使用默认参数;

  函数定义时,默认参数  需放在  非默认参数  后面;

  示例代码如下:

# 函数定义时,默认参数需放在非默认参数后面
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)
View Code

  执行结果如下:

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
View Code

 

  不定长参数 (*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)
View Code

  执行结果如下:

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
View Code

 

  通过一个函数的定义来理解  ' *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)
View Code

  执行结果如下:

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
View Code

 

  通过一个函数的调用来理解  '  **  '  的作用

    函数调用时,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)
View Code

  执行结果如下:

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
View Code

 

   在函数调用中  ”**”  做了什么?
   它 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)
View Code

执行结果如下:

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
View Code

 

   

 参考资料:https://www.runoob.com/python3/python3-function.html

     https://www.cnblogs.com/cwind/p/8996000.html

 

posted @ 2021-07-26 19:14  空-山-新-雨  阅读(250)  评论(0编辑  收藏  举报