Python札记 -- 参数魔法
在上一篇随笔《Python凡人笔记 -- 装饰器》中有园友提出我对Python中的参数魔法表述得不是很明确,故借此机会总结一下,再结合几个例子,希望对大家有帮助。另外竹风使用的是 Python 2.6.6
参考资料:《Python基础教程》(第2版)Magnus Lie Hetland
一、Python的函数返回些什么?
一般说的函数,总会在计算之后返回点什么。像在 Pascal 里面,就有分函数和过程。让我们一起从例子里面看看 Python 的函数到底会返回些什么。
1 def test(): 2 print "This is printed" 3 return 4 print "This is not"
这里的return语句只起到结束函数的作用:
1 >>> x = test() 2 This is printed 3 4 >>> x 5 >>> 6 7 >>> print x 8 None
可以看到,第二个print语句被跳过了。单单看 x 好像没有任何东西,通过 “print x” 我们可以看到一个熟悉的值:None。
这么看来,在Python里面,所有的函数都会返回值;当不需要它们返回值的时候,它们就返回None。
二、什么类型的参数可以修改?
函数通过参数来获得一系列的值。在Python中,字符串(以及数字和元组)是不可变的,即无法被修改(也就是说只能用新的值覆盖),用学术点的话来说:在函数内为不可变类型的参数赋予新值不会改变外部任何变量的值。
1 >>> def try_to_change(n): 2 ... n = "Mr Gumby" 3 ... 4 >>> name = "Mrs Entity" 5 >>> try_to_change(name) 6 >>> name 7 'Mrs Entity'
我们可以看到,name 虽然作为参数传递到函数中,但是最后 name 的值并没有任何改变。其实上面的代码工作方式类似于下面这样:
1 >>>name = "Mrs Entity" 2 >>>n = name #相当于传参数 3 >>>n = "Mr Gumby" #在函数内部给n一个新的字符串 4 >>>name 5 'Mrs Entity'
那么如果我们传的参数是一个可变的数据结构呢,比如列表?估计大家已经能猜到结果了。
1 >>> def change(n): 2 ... n[0] = "Mr Gumby" 3 ... 4 >>> name = ["Mrs Entity", "Mrs Thing"] 5 >>> change(name) 6 >>> name 7 ['Mr Gumby', 'Mrs Thing']
这里发现参数的值改变了,这也是与前面的例子中最重要的区别。要弄清楚的是,当两个变量同时引用一个列表的时候,它们的确是同时引用了一个列表。如果想避免出现这种情况,可以复制一个列表的副本。具体做法就是传递参数的时候,将列表的分片作为参数,比如:change(name[:])。这样的话,原始的列表就是安全的。
PS:竹风刚入门的时候曾经犯过将原始列表传入函数的错误,关键是函数里面有一个 remove 操作,结果大家也能猜到了。。。
那如果要对一个不可变的参数进行操作呢?比如一个数字,这又该怎么办?
这个时候我们应该从函数中返回所有需要的值,如果值多于一个拿就用元组的形式返回。例如,将变量的数值增加1的函数可以这么写:
1 >>> def inc(x):return x + 1 2 ... 3 >>> foo = 10 4 >>> foo = inc(foo) 5 >>> foo 6 11
如果真的想改变参数的话,我们可以使用一点小技巧,将值放在列表中(还记得列表是可修改的么?):
1 >>> def inc(x): x[0] = x[0] + 1 2 ... 3 >>> foo = [10] 4 >>> inc(foo) 5 >>> foo 6 [11]
使用哪种方式,全凭个人喜好~~
三、位置参数,关键字参数,默认参数
到目前为止,前面例子中使用的都是位置参数,因为它们的位置很重要——事实上比它们的名字更重要。先看些简单的列子,来看看为什么会引入关键字参数。
1 >>> def hello_1(greeting, name): 2 ... print "%s, %s!" % (greeting, name) 3 ... 4 >>> def hello_2(name, greeting): 5 ... print "%s, %s!" % (name, greeting) 6 ... 7 >>> hello_1("Hello", "World") 8 Hello, World! 9 >>> hello_2("World", "Hello") 10 World, Hello!
这两个函数所实现的功能是完全一样的,唯一的区别就是参数的顺序。当参数很多的时候,竹风觉得参数的顺序是很难记住的。为了让事情简单些,我们可以提供参数的名字。
1 >>> hello_1(greeting = "Hello", name = "World") 2 Hello, World! 3 >>> hello_1(name = "World", greeting = "Hello") 4 Hello, World! 5 >>> hello_2(greeting = "Hello", name = "World") 6 World, Hello!
提供了参数的名字后,顺序就无关紧要的,就好像上面的 hello_1 调用。唯一要注意的,就是参数名和值一定要对应,不然就会出现 hello_2 那样输出 “World Hello!”了。
这类使用参数名提供的参数叫做关键字参数。主要作用在于可以明确每个参数的作用,也就避免了下面这样奇怪的调用:
1 >>>stroe("Mr Brainsample", 10, 20, 13, 5) 2 3 >>>stroe(patient="Mr Brainsample", hour=10, minute=20, day=13, month=5)
竹风以为,大部分园友看见第一种调用的时候估计是虎躯一震的。。。第二种调用虽然打的字多了点,但是参数的含义变得更加清晰,而且就算弄乱了参数的顺序,对于程序的功能也没有任何影响。
关键字参数最实用的地方在于可以在函数中给参数提供默认值,嘎嘎,再也不用担心调用函数的时候漏参数了~~
>>> def hello_3(greeting="Hello", name="World"): ... print "%s, %s!" % (greeting, name) ... >>> hello_3() #使用默认参数 Hello, World! >>> hello_3('Greetings') #使用位置参数将值传给greeting Greetings, World! >>> hello_3('Greetings','God') #同时使用位置参数 Greetings, God! >>> hello_3('Greetings',name = 'Tom') #位置参数和关键字参数混用 Greetings, Tom! >>> hello_3(name = 'Jerry') #只使用关键字参数指定name Hello, Jerry!
最后关于位置参数和关键字参数需要注意的是:同时使用位置和关键字参数的时候,必须把位置参数放置在关键字参数的前面,否则,解释器就不知道这些参数到底应该处在什么位置了。
四、收集参数与解开参数
铺垫了这么久,终于来到今天的两大Boss面前了。位置参数拉好仇恨,关键字参数做好治疗,其他人全力输出吧!(博主wow五人本打多了。。。无视就好。。。)
先说说收集参数,在定义函数时,*params 收集其余的位置参数(parameter),返回元组;**kwparams 收集其余的关键字参数(key word parameter),返回字典。
有时候能提供任意数量的参数是相当方便的,比如一个函数 add 可以求任意个数字的和,add(1,2,3) 和 add(1,2,3,4,5) 都能给出正确结果。
用户可以给函数提供任意多的参数,实现起来也不难。注意例子中虽然只提供了一个参数,但是前面加上了个星号。
1 >>> def print_params(*params): 2 ... print params 3 ... 4 >>> print_params('Testing') 5 ('Testing',) 6 >>> print_params('Testing',1,2,3) 7 ('Testing', 1, 2, 3)
可以看到,结果作为元组打印出来。参数前的星号将所有传进来的参数放置在同一个元组中。也可以说是把这些值收集起来,然后使用。当然也可以联合普通参数来使用:
1 >>> def print_params_2(title, *params): 2 ... print "title =",title 3 ... print params 4 ... 5 >>> print_params_2("Test2", 1, 2, 3) 6 title = Test2 7 (1, 2, 3) 8 >>> print_params_2("Test3") 9 title = Test3 10 ()
完全没问题!所以星号的意思就是“收集其余的位置参数”。如果不提供任何收集的元素,params就是个空元组。
让我们看下关键字参数的“收集”操作。
1 >>> def print_params_3(**kwparams): 2 ... print kwparams 3 ... 4 >>> print_params_3(x=1, y=2, z=3) 5 {'y': 2, 'x': 1, 'z': 3}
返回的是字典而不是元组。将它们放在一起看看:
>>> def print_params_4(x, y, z=3, *pospar, **keypar): ... print x, y, z ... print pospar ... print keypar ... >>> print_params_4(1, 2, 3, 5, 6, 7, foo='A', bar='B') 1 2 3 (5, 6, 7) {'foo': 'A', 'bar': 'B'} >>> print_params_4(1, 2, 3) 1 2 3 () {}
ok,跟我们期望的结果没有差别。
收集参数打完了,再来打展开参数。
展开参数,在调用函数时,*params 将元组拆分为位置参数(parameter)传入;**kwparams 将字典拆分为关键字参数(key word parameter)传入。
这是两个典型的例子:
1 >>> def add(x,y): return x + y 2 ... 3 >>> params = (1, 2) 4 >>> add(*params) 5 3 6 >>> def hello_3(greeting="Hello", name="World"): 7 ... print "%s, %s!" % (greeting, name) 8 ... 9 >>> kwparams = {'name': 'Sir Robin', 'greeting': 'Well met'} 10 >>> hello_3(**kwparams) 11 Well met, Sir Robin!
最后我们看看这几种方式一起使用的情况:
1 >>> def finally_test(x, y, z=3, *params, **kwparams): #参数的顺序应该为:位置参数,关键字参数,*params,**kwparams 2 ... print "pos x =",x 3 ... print "pos y =",y 4 ... print "key z =",z 5 ... print "params =",params 6 ... print "kwparams =",kwparams 7 ... 8 >>> list = [1,2,3,4,5] 9 >>> dict = {"foo":"A", "bar":"B"} 10 11 >>> finally_test(1,2,*list,**dict) #没有指定z的值,所以将list[0]作为z的值,其他收集为params 12 pos x = 1 13 pos y = 2 14 key z = 1 15 params = (2, 3, 4, 5) 16 kwparams = {'foo': 'A', 'bar': 'B'} 17 18 >>> finally_test(1,2,3,list,dict) #错误的调用方法,会将dict也认为是个位置参数 19 pos x = 1 20 pos y = 2 21 key z = 3 22 params = ([1, 2, 3, 4, 5], {'foo': 'A', 'bar': 'B'}) 23 kwparams = {} 24 25 >>> finally_test(1,2) #没有多余的位置参数和关键字参数的情况 26 pos x = 1 27 pos y = 2 28 key z = 3 29 params = () 30 kwparams = {} 31 32 >>> finally_test(1,2,3,*list,**dict) #正确的调用方式 33 pos x = 1 34 pos y = 2 35 key z = 3 36 params = (1, 2, 3, 4, 5) 37 kwparams = {'foo': 'A', 'bar': 'B'}
其实一般情况下会这么定义函数:
def foo(*params,**kwparams):
pass
到这里就总结完了,希望对大家有用。如有不足,欢迎大家指正交流,谢谢^_^
转载于:https://www.cnblogs.com/PandaBamboo/archive/2013/02/05/2892731.html
Python札记 -- 参数魔法相关推荐
- python args kw_Python基础-参数魔法,*args,**kwags
最近在带着新成员一起学习<Python基础教程>这本书,看到参数魔法的时候 突然感觉好多术语真的不知道呀~ Python参数:位置参数,关键字参数 经常看Python我们肯定经常看见,下面 ...
- python中的魔法参数:*args和**kwargs
def foo(*args, **kwargs): print 'args = ', args print 'kwargs = ', kwargs print '------------------- ...
- 刻意练习:Python基础 -- Task11. 魔法方法
背景 我们准备利用17天时间,将 "Python基础的刻意练习" 分为如下任务: Task01:变量.运算符与数据类型(1day) Task02:条件与循环(1day) Task0 ...
- Python札记 -- 测试优先
竹风看的第一本有关Python的书是<Dive Into Python>(简称DIP),本人觉得这本书写得是相当不错的(当然竹风无意卷入关于这本书是好是坏的争论,只要找到适合自己的资料和学 ...
- (Python高级编程)第二章:Python中的魔法函数
文章目录 一:什么是魔法函数 (1)魔法函数 (2)作用 二:Python中的魔法函数 (1)字符串表示 (2)集合序列相关 (3)迭代相关- (4)可调用 (5)with上下文管理器 (6)数制转换 ...
- python深度讲解_《深度剖析CPython解释器》21. Python类机制的深度解析(第五部分): 全方位介绍Python中的魔法方法,一网打尽...
楔子 下面我们来看一下Python中的魔法方法,我们知道Python将操作符都抽象成了一个魔法方法(magic method),实例对象进行操作时,实际上会调用魔法方法.也正因为如此,numpy才得以 ...
- 从零开始学Python编程之魔法方法
大家好,我是岛上程序猿,欢迎关注! Python中的魔法方法是一种特殊方法,以双下划线开头和结尾,并且可以在类定义中定义,用于执行特定的操作.在本文中,我们将介绍魔法方法的作用.如何使用它们以及Pyt ...
- Python札记1_列表list
写于开始之前 笔者即将开始写一个系列的<Python札记>.本系列的札记主要是自学齐伟老师<跟老齐学Python轻松入门>一书整理而来.书第一遍断断续续花了5个月,第二遍边看边 ...
- Python的类和对象的介绍,定义类和对象,定义实例方法和属性以及Python中的魔法方法
Day09新手小白学python 第九节 Python的类和对象的介绍,定义类和对象,定义实例方法和属性以及Python中的魔法方法 目录 Day09新手小白学python 前言 一.面向对象介绍 二 ...
最新文章
- ATS cache中的几个数据结构图收集
- JQuery 动态创建表单,并自动提交
- C#学习笔记(八)——定义类的成员
- pve安装黑群晖直通硬盘_在Proxmox VE(PVE)安装黑群晖
- 工具类软件操作手册_全套广联达软件学习资料合集:教程+实例讲解+操作手册,一文搞定...
- 代码: 0x80131500_微软应用商店错误代码“0x80131500”怎么修复?
- Spring框架—IoC容器
- 相加等于目标值的两个数
- c++ 检查远程主机端口_漏洞通告:Windows RDP服务远程代码执行漏洞通告(CVE-2019-0708)...
- linux版本i686,在Ubuntu中'i686'是什么意思? - Ubuntu问答
- AD18快速简单入门,画电路原理图以及PCB图
- 章草、今草、狂草是草书的三种书写表现方式,你更喜欢哪一种?
- U盘做成系统盘后如何恢复成普通U盘?
- git设置 mergetool为kdiff3
- 【Vue知识点- No5.】生命周期、axios、购物车案例
- 苹果手机怎么验证app_苹果序列号查询 未验证怎么办?
- Vue2项目引入mars3d
- Spring Security Oauth2 令牌增加额外信息
- javaSE基础全覆盖
- Java实现的一个简易网络画板
热门文章
- idea调试源代码c语言,IDEA阅读spring源码并调试
- 炒币风潮又起,区块链不该这么玩
- VsCode镜像下载(国内镜像源,高速秒下)
- JSON树转换成线性列表(python)
- html中tr中加判断换行符,深入解析HTML的table表格标签与相关的换行问题
- 倍思途享伸缩车载充电器体验:乐享车载快充,让爱车少些凌乱
- html画布动漫人物,canvas画布画卡通人物--哆啦A梦
- 解决“应用程序正常初始化(0x00000005)失败”错误
- Excel如何提取单元格中最后一次出现的数值
- 年终总结 | 怎样识别并投资高效能人才?