发一下牢骚和主题无关:
在上一篇笔随《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
到这里就总结完了,望希对大家用有。若有足不,迎欢大家正指交流,感谢^_^
文章结束给大家分享下程序员的一些笑话语录: 马云喜欢把自己包装成教主,张朝阳喜欢把自己包装成明星,李彦宏喜欢把自己包装成的很知性,丁磊喜欢把自己包装的有创意,李开复总摆出一副叫兽的样子。看来的。其实我想说,缺啥补啥,人之常情。
相关资源:Java 面经手册·小傅哥(公众号:bugstack虫洞栈).pdf