函数定义时圆括号内是使用逗号分隔开的形式参数列表(parameters),一个函数可以没有参数,但是定义和调用时一对圆括号必须要有,表示这是一个函数并且不接受参数。函数调用时向其传递实参(arguments),根据不同的参数类型,将实参的值或引用传递给形参。

  定义函数时,对参数个数并没有限制,如果有多个形参,则需要使用逗号进行分隔。例如,下面的函数用来接受2个参数,并输出其中的最大值。

1 def printMax(a,b):
2     if a > b :
3         print(a,'is the max')
4     else:
5         print(b,'is the max')

  注意:这里只是为了,演示,忽略了一些细节,如果输入的参数不支持比较运算符,则会出错,可以参考后面第7章中介绍的异常结构来解决这个问题。

  对于绝大多数情况下,在函数内部直接修改形参的值不会影响实参。例如:

 1 def addOne(a):
 2     print(a)   #输出原变量 a 的值
 3     a += 1
 4     print(a)   #这条语句会得到一个新的变量a
 5
 6 a = 3
 7 addOne(3)
 8
 9 # 3
10 # 4
11
12 print(a)
13 # 3

  从运行结果可以看出,在函数内部修改了形参a的值,但是当函数运行结束以后,实参a的值并没有被修改。然而,在有些情况下,可以通过特殊的方式在函数内部修改实参的值,例如:

 1 >>> def modify(v):             #修改列表元素值
 2     v[0] += 1
 3
 4
 5 >>> a = [2]
 6 >>> modify(a)
 7 >>> a
 8 [3]
 9 >>>
10 >>>
11 >>> def modify(v,item):       #为列表增加元素
12     v.append(item)
13
14
15 >>> a = [2]
16 >>> modify(a,3)
17 >>> a
18 [2, 3]
19 >>>
20 >>>
21 >>>
22 >>> def modify(d):            #修改字典元素值或为字典增加元素
23     d['age'] = 38
24
25
26 >>> a = {'name':'Dong','age':37,'sex':'Male'}
27 >>>
28 >>> modify(a)
29 >>>
30 >>> a
31 {'name': 'Dong', 'sex': 'Male', 'age': 38}
32 >>> 

  也就是说,如果传递给函数的是Python可变序列,并且在函数内部使用下标或序列自身支持的方式为可变序列增加、删除元素或修改元素值时,修改后的结果是可以反映到函数之外的,即实参也得到了相应的修改。

1 默认值参数

  在定义函数时,Python支持默认参数,即在定义函数时为形参设置默认值。在调用带有默认值参数的函数时,可以不用为设置了默认值的参数进行传值,此时函数将会直接使用函数定义时设置的默认值,也可以通过显式赋值来替换其默认值。也就是说,在调用函数时是否为默认值参数传递实参是可选的,具有较大的灵活性。带有默认值参数的函数定义语法如下:

1 def 函数名(...,形参名 = 默认值):
2     函数体

  可以使用 函数名.__defaults__ 随时查看函数所有默认值参数的当前值,其返回值为一个元组,其中的元素依次表示每个默认值参数的当前值。

 1 >>> def say(message,times = 1):
 2     print((message + ' ')* times)
 3
 4
 5 >>>
 6 >>>
 7 >>> dir(say)
 8 ['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__',     '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__',     '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__',    '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
 9 >>>
10 >>> say.__defaults__
11 (1,)
12 >>> 

  调用该函数时,如果只为第一个参数传递实参,则第二个参数使用默认值 1 ;如果为第二个参数传递参数,则不再使用默认值 1 ,而是使用调用者显式传递的值。

1 >>> say('hello')
2 hello
3 >>>
4 >>> say('hello',3)
5 hello hello hello
6 >>>
7 >>> say('hi',5)
8 hi hi hi hi hi
9 >>> 

  注意:在定义带有默认值参数的函数时,默认值参数必须出现在函数参数列表的最右端,任何一个默认值参数右边都不能再出现非默认值参数。

  注意:一般情况下,都是调用函数时为其传递参数,这时形参的值由调用函数时实参的值确定。但如果函数的默认值参数不是调用时传递的,而是通过其他方式对其赋值,那么默认值参数的值可能会在函数定义是确定,而不是函数调用时。例如:

 1 >>> i = 5
 2 >>> def demo(v):
 3     print(v)
 4
 5
 6 >>> i = 6
 7 >>> demo(i)
 8 6
 9 >>>
10 >>> i = 5
11 >>>
12
13 >>> def demo(v = i):     #等价于def demo(v = 5):
14     print(v)             #相当于定义函数时设置默认值参数 5
15
16
17 >>> i = 6
18 >>>
19 >>> demo()
20 5
21 >>> 

  注意:多次调用函数并且不为默认值参数传递值时,默认值参数只在第一次调用时进行解释,对于列表,字典这样可变类型的默认值参数,这一点可能会导致很严重的逻辑错误,而这种错误或许会耗费大量精力来定位和纠正。例如:

 1 >>>
 2 >>> def demo(newitem,old_list=[]):
 3     old_list.append(newitem)
 4     return old_list
 5
 6 >>>
 7 >>> print(demo('5',[1,2,3,4]))
 8 [1, 2, 3, 4, '5']
 9 >>>
10 >>> print(demo('aaa',['a','b']))
11 ['a', 'b', 'aaa']
12 >>>
13 >>> print(demo('a'))
14 ['a']
15 >>>
16 >>> print(demo('b'))
17 ['a', 'b']
18 >>>
19 >>> print(demo('c'))
20 ['a', 'b', 'c']
21 >>> 

  上面的函数使用列表作为默认值参数,由于其可记忆性,连续多次调用该函数而不给该参数传值,再次调用时将保留上一次调用的结果,从而导致很难发现的错误。下面的代码就不存在这个问题:

1 >>>
2 >>> def demo(newitem,old_list=None):
3     if old_list is None:
4         old_list = []
5     old_list.append(newitem)
6     return old_list
7
8 >>> 

  

2 关键字参数

  关键字参数主要指调用函数时的参数传递方式,与函数定义无关。通过关键字参数可以按参数名字传递值,实参顺序可以和形参顺序不一致,但不影响参数值的传递结果,避免了用户需要牢记参数位置和顺序的麻烦,使得函数的调用和参数传递更加灵活方便。

 1 >>>
 2 >>> def demo(newitem,old_list=None):
 3     if old_list is None:
 4         old_list = []
 5     old_list.append(newitem)
 6     return old_list
 7
 8 >>>
 9 >>>
10 >>>
11 >>>
12 >>> def demo(a,b,c = 5):
13     print(a,b,c)
14
15
16 >>>
17 >>> demo(3,7)
18 3 7 5
19 >>>
20 >>> demo(a=7,b=3,c=6)
21 7 3 6
22 >>>
23 >>> demo(c=8,a=9,b=0)
24 9 0 8
25 >>> 

3 可变长度参数

  可变长度参数在定义函数时主要有两种形式:*parameter 和 **parameter,前者用于接受任意多个实参并将其放在一个元组中,后者接受类似于关键字参数一样显式赋值形式的多个实参并将其放入字典中。

  下面代码演示了第一种形式可变长度参数的用法,即无论调用该函数时传递了多少实参,一律将其放入元组中:

 1 >>>
 2 >>> def demo(*p):
 3     print(p)
 4
 5
 6 >>> demo(1,2,3)
 7 (1, 2, 3)
 8 >>>
 9 >>> #其实 1,2,3 本身就是元组
10 >>> a = 1,2,3
11 >>> type(a)
12 <class 'tuple'>
13 >>>
14 >>> demo(1,2,3,4,5,6,7)
15 (1, 2, 3, 4, 5, 6, 7)
16 >>> 

  下面的代码演示了第二种形式可变长度参数的用法,即在调用函数时自动将接收的参数转换为字典:

 1 >>>
 2 >>> def demo(**p):
 3     for item in p.items():
 4         print(item)
 5
 6
 7 >>> demo(x = 1,y = 2,z = 3)
 8 ('y', 2)
 9 ('z', 3)
10 ('x', 1)
11 >>> 

  注意:Python定义函数时可以同时使用位置参数、关键字参数、默认值参数和可变长度参数,但是除非真的很必要,否则请不要这样用,因为这会使得代码非常混乱而严重降低可读性,并导致程序查错非常困难。另外,一般而言,一个函数如果可以接受很多不同类型参数的话,很可能是函数设计得不好,例如函数功能过多,需要进行必要的拆分和重新设计,以满足模块高内聚的要求。

4 传递参数时的序列解包

  调用含有多个参数的函数时,可以使用Python列表、元组、集合、字典以及其他可迭代对象作为实参,并在实参名称前加一个星号,Python解释器将自动进行解包,然后传递给多个单变量形参。

 1 >>>
 2 >>> seq = [1,2,3]
 3 >>>
 4 >>> demo(*seq)
 5 6
 6 >>>
 7 >>> tup = (1,2,3)
 8 >>>
 9 >>> demo(*tup)
10 6
11 >>>
12 >>>
13 >>> dic = {1:'a',2:'b',3:'c'}
14 >>> demo(*dic)
15 6
16 >>>
17 >>> set = {1,2,3}
18 >>> demo(*set)
19 6
20 >>>
21 >>> demo(*dic.values())
22 abc
23 >>>
24 >>> demo(*dic.keys())
25 6
26 >>>
27 >>> demo(*dic.items())
28 (1, 'a', 2, 'b', 3, 'c')
29 >>> 

  小提示:

    (1)字典对象作为实参时默认使用字典的“键”,如果需要将字典中的“键:值”元素作为参数则需要使用items()方法明确说明,如果需要将字典的“值”作为参数则需要调用字典的values()方法明确说明;

    (2)实参中元素个数与形参个数必须相等,否则将出现错误。

  

  注意:调用函数时如果对实参使用一个星号(*)进行序列解包,那么这些解包后的实参将会被当做普通位置参数对待,并且会在关键参数和使用两个星号(**)进行序列解包的参数之前进行处理。

 1 >>>
 2 >>> def demo(a,b,c):   #定义函数
 3     print(a,b,c)
 4
 5
 6 >>>
 7 >>> demo(*(1,2,3))     #调用,序列解包
 8 1 2 3
 9 >>>
10 >>> demo(1,*(2,3))     #位置参数和序列解包同时使用
11 1 2 3
12 >>>
13 >>> demo(1,*(2,),3)
14 1 2 3
15 >>>
16 >>>
17 >>> demo(a = 1,*(2,3))          #序列解包相当于位置参数,优先处理
18 Traceback (most recent call last):
19   File "<pyshell#47>", line 1, in <module>
20     demo(a = 1,*(2,3))          #序列解包相当于位置参数,优先处理
21 TypeError: demo() got multiple values for argument 'a'
22 >>>
23 >>> demo(b = 1,*(2,3))
24 Traceback (most recent call last):
25   File "<pyshell#49>", line 1, in <module>
26     demo(b = 1,*(2,3))
27 TypeError: demo() got multiple values for argument 'b'
28 >>>
29 >>>
30 >>> demo(c = 1,*(2,3))
31 2 3 1
32 >>>
33 >>>
34 >>>
35 >>>
36 >>> demo(**{'a':1,'b':2},*(3,))   #序列解包相当于位置参数,优先处理
37 SyntaxError: iterable argument unpacking follows keyword argument unpacking
38 >>>
39 >>>
40 >>>
41 >>>
42 >>>
43 >>> demo(*(3,),**{'a':1,'b':2})
44 SyntaxError: invalid character in identifier
45 >>>
46 >>> demo(*(3,),**{'a':1,'b':2})
47 Traceback (most recent call last):
48   File "<pyshell#72>", line 1, in <module>
49     demo(*(3,),**{'a':1,'b':2})
50 TypeError: demo() got multiple values for argument 'a'
51 >>>
52 >>>
53 >>> demo(*(3,),**{'c':1,'b':2})
54 3 2 1
55 >>> 

转载于:https://www.cnblogs.com/avention/p/8597775.html

3.3.2 函数参数不得不说的几件事相关推荐

  1. WHM不可不说的几件事?

    尊敬的51cto会员,我是[文德数据]的90小编小宇; 主机商7 今天给大家说一下WHM,(Web host manager),简称主机管理.首先我们来彻底的了解下它的主要作用. 1,模块选择问题,在 ...

  2. 软件卸载不得不说的几件事

    电脑用久了,软件也装了不少,但并不是每一款软件都那么让人心动,希望永远与之相伴,于是装了卸,卸了装的事不少,但似乎目前还没有一款软件能够痛痛快快地来,痛痛快快地走,它们总喜欢在你的Windows中留点 ...

  3. 千万不要把 bool 当成函数参数

    我们有很多 Coding Style 或 代码规范. 但这一条可能会经常被我们所遗忘,就是我们 经常会在函数的参数里使用bool参数,这会大大地降低代码的可读性. 不信?我们先来看看下面的代码. 当你 ...

  4. 千万不要把bool类型当成函数参数(转自CoolShell.cn)

    我们有很多Coding Style 或 代码规范.但这一条可能会经常被我们所遗忘,就是我们经常会在函数的参数里使用bool参数,这会大大地降低代码的可读性.不信?我们先来看看下面的代码. 当你读到下面 ...

  5. Go 学习笔记(65)— Go 中函数参数是传值还是传引用

    Go 语言中,函数参数传递采用是值传递的方式.所谓"值传递",就是将实际参数在内存中的表示逐位拷贝到形式参数中.对于像整型.数组.结构体这类类型,它们的内存表示就是它们自身的数据内 ...

  6. C++ 笔记(13)— 函数(函数声明、函数定义、函数调用[传值、指针、引用]、函数参数默认值、函数重载)

    每个 C++ 程序都至少有一个函数,即主函数 main() ,所有简单的程序都可以定义其他额外的函数. 1. 函数声明 函数声明告诉编译器函数的名称.返回类型和参数.函数声明包括以下几个部分: ret ...

  7. python基础(三元运算+深浅拷贝+函数参数)

    三元运算 三元运算,又称三目运算,主要作用是减少代码量,是对简单的条件语句的缩写. 1 书写格式: 2 result = 值1 if 条件 else 值2 3 即如果条件成立,则将值1赋给result ...

  8. C指针6:指针变量作为函数参数

    在C语言中,函数的参数不仅可以是整数.小数.字符等具体的数据,还可以是指向它们的指针.用指针变量作函数参数可以将函数外部的地址传递到函数内部,使得在函数内部可以操作函数外部的数据,并且这些数据不会随着 ...

  9. 双重指针作为函数参数的妙用

    双重指针作为函数参数,可以在函数函数内部修改外部指针的值.主要用法包括: 1. 在函数内部分配内存,作为函数参数返回: 2. 在函数内部设置指针为空: #include <stdio.h> ...

最新文章

  1. linux 消息队列实例
  2. 《追风行动》有点儿意思
  3. python矩阵运算与线形代数_[译] 线性代数:矩阵基本运算
  4. 开源前端 可视化大数据交互前端动态模板
  5. 年薪40W,如何高效准备大厂AI算法岗面试?
  6. 2021-2025年中国中子发生器行业市场供需与战略研究报告
  7. 金万维异速联服务器重装,金万维异速联服务器配置说明
  8. 计算机地址聚合,cidr怎么算?cidr地址聚合快速算法
  9. 光影精灵usb安装linux,惠普光影精灵5笔记本怎么装win10系统(uefi+gpt)
  10. win10 安装 framework7 报错解决思路和方法
  11. 阿里云服务器ECS有哪些功能特性?
  12. 20162330 第十周 蓝墨云班课 十字链表
  13. [摄影学习]-ZFC进阶操作学习
  14. 计算机提示无法验证发布者,win7系统取消“无法验证发布者”提示框的操作技巧...
  15. 桌面增加了IE图标无法删除
  16. 笑面的学校日常(14)最近一次更新2017 04 06
  17. android Google Map API V2 (key 申请)
  18. 小学老师工资多少一个月_小学教师工资待遇现在怎么样?乡村老教师含泪哭诉!...
  19. android app 原生 小米手机 TextView 不显示文字
  20. php 中文 utf8,php utf8跟utf-8的区别

热门文章

  1. SQL删除重复数据方法
  2. python twisted 笔记
  3. ios开发趋势_2020年将成为iOS应用开发的主要趋势
  4. linux内核功能有,好消息!LINUX内核2.6.18终于支持实时功能了
  5. 如何创建和获取正则对象?
  6. java hanoi_Hanoi问题java解法
  7. python 100例(10)
  8. 在python中调用js或者nodejs要使用PyExecJs第三方包。
  9. 润乾报表永久授权说明
  10. Exchange Server 2013 LAB Part 4.内部客户端访问