一、函数定义方式
函数定义用关键字def
,其参数传递不用设置类型,也不用定义返回,然后在函数名称后加上:
号,这点和java
很不一样,相对来说更加简单了;另外包含关系上用四个空格来标识,而非java的;
号;
如下为一个范例,定义了一个函数用来生成任意上界的菲波那契数列:
# -*- coding: UTF-8 -*-
def fib(n):
a,b = 0,1
while a<n:
print a,
a,b = b, a+b
if __name__ == '__main__':
a = fib(2000)
结果:
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
二、高级用法
除了最简单的传参方法后还有特别的传参方法,有三种可用方式,下面一一做说明;
大体来说,参数传递分为必选参数和可选参数(注意必选参数必须在前面),可选参数在调用函数的时候可传可不传,这点比java
要好用(用java得多写好几个函数);
1、默认参数值
默认参数值即在函数定义的时候为一个或者多个参数定义一个默认值,如果调用参数的时候不传入该参数则自动使用默认参数值,下面是一个范例:
def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
while True:
ok = raw_input(prompt)
if ok in ('y', 'ye', 'yes'):
return True
if ok in ('n', 'no', 'nop', 'nope'):
return False
retries = retries - 1
if retries < 0:
raise IOError('refusenik user')
print complaint
在这个例子中参数retries
和complaint
这两个参数即为可选参数,其=
号后边的即为默认参数值;
那么调用的时候我们就可以这样:
- 只传入默认参数
prompt
ask_ok('Do you really want to quit?')
- 给出一个可选的参数:
ask_ok('OK to overwrite the file?', 2)
- 或者给出所有的参数:
ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')
注意:这里注意参数顺序不要错误,另外默认参数值只会被赋值一次,但也有例外情况,譬如默认值是个列表、字典或者大多数类的实例。例如,下面的函数在后续调用过程中会累积(前面)传给它的参数:
>>> def f(a,L=[0]):
L.append(a)
return L
>>> print f(1)
[0, 1]
>>> print f(2)
[0, 1, 2]
>>> print f(3)
[0, 1, 2, 3]
为什么会这样呢,解释如下:
Python函数在定义的时候,默认参数L
的值就被计算出来了,即[]
,因为默认参数L
也是一个变量,它指向对象[]
,每次调用该函数,如果改变了L
的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]
了。
定义默认参数要牢记一点:默认参数必须指向不变对象!
可以像如下这样修改就不会有这个问题了:
>>> def ff(a, L=None):
if L is None:
L=[]
L.append(a)
return L
>>> print ff(1)
[1]
>>> print ff(2)
[2]
>>> print ff(3)
[3]
如上所示,结果就不会再出现前次传入的值会加入后边的情况了;
函数调用的时候可选参数如果采用前面那种方式则必然得注意顺序,譬如我有三个可选参数,但是我第一个可选参数不想传咋办呢,用前面那种方式显然不可行,那么就可以用关键字参数
了,运行key=value
方式可以忽略顺序,也可以自定义传入的可选参数值,范例如下:
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
print "-- This parrot wouldn't", action,
print "if you put", voltage, "volts through it."
print "-- Lovely plumage, the", type
print "-- It's", state, "!"
接受一个必选参数( voltage
)以及三个可选参数( state
, action
, 和 type
)。可以用以下的任一方法调用:
parrot(1000) # 1 positional argument
parrot(voltage=1000) # 1 keyword argument
parrot(voltage=1000000, action='VOOOOOM') # 2 keyword arguments
parrot(action='VOOOOOM', voltage=1000000) # 2 keyword arguments
parrot('a million', 'bereft of life', 'jump') # 3 positional arguments
parrot('a thousand', state='pushing up the daisies') # 1 positional, 1 keyword
不过以下几种调用是无效的:
parrot() # required argument missing
parrot(voltage=5.0, 'dead') # non-keyword argument after a keyword argument
parrot(110, voltage=220) # duplicate value for the same argument
parrot(actor='John Cleese') # unknown keyword argument
注意:这种关键字参数的传参方法适用于所有的参数,即包括必选参数和可选参数;
2、可变参数
python对于定义函数的时候的参数还提供了一种方法,即可变参数,可变参数的意思就是传入的参数的个数是可变的,可以是0个,1个或者无数个;
譬如我们需要定义一个函数,入参为一个元组或者列表,可以这样写:
>>> def c(numbers):
sum=0
for n in numbers:
sum=sum+n*n
return sum
调用的时候就需要先定义一个元组或者列表,如下:
>>> c([1,2,3])
14
>>> c((1,3,5,7))
84
其实是比较麻烦的,那么又没简单的方法呢,有的,那就是在numbers
前面加一个*
号即可,这样调用的时候就不用再初始化了,如下:
>>> def calc(*numbers):
sum=0
for n in numbers:
sum=sum+n*n
return sum
调用时就可以这样:
>>> calc(1,2,3)
14
>>> calc()
0
这样确实比前面那个例子要方便很多;
注意:可选参数不要加两个*argu
,这样程序会分不清的;
3、关键字参数
那么如果我参数是需要传入字典呢?可以使用**kw
的方式,请看如下范例:
定义一个函数:
>>> def cheeseshop(kind,*arguments,**keywords):
print "-- Do you have any", kind, "?"
print "-- I'm sorry, we're all out of",kind
for arg in arguments:
print arg
print "-"*40
keys=sorted(keywords.keys())
for kw in keys:
print kw, ":", keywords[kw]
这个函数除了一个必选参数kind
,第二个参数需要传入的是一个tuple
或者list
,第三个参数呢需要传入一个字典;
如前所说这种参数写法是不需要先定义元组或者列表或者序列的,可以直接当参数传入,如下即为调用方法:
>>> cheeseshop("Limburger","It's very runny,sir.","It's really very, VERY runny, sir.",shopkeeper='Michael Palin',client="John cleese",sketch='Cheese Shop Sketch')
-- Do you have any Limburger ?
-- I'm sorry, we're all out of Limburger
It's very runny,sir.
It's really very, VERY runny, sir.
----------------------------------------
client : John cleese
shopkeeper : Michael Palin
sketch : Cheese Shop Sketch
如上所示,传入的第一个参数值Limburger
是必选参数kind
,第二个参数到第三个参数为元组,后边几个明显是键值对模式的即为字典了。
注意:在打印关键字参数之前,通过对关键字字典keys()
方法的结果进行排序,生成了关键字参数名的列表;如果不这样做,打印出来的参数的顺序是未定义的。
4、命名关键字参数
这个和**kw
有点类似,区别在于,前面那种方式调用的时候传入的字典很自由,但是如果我们想控制调用的时候传入的字典的key
呢?可以添加一个特殊分隔符*
,*
后面的参数被视为命名关键字参数,范例如下:
>>> def person(name, age, *, city, job):
... print (name, age, city,job)
...
上面的代码中传入的dict
只能包含city
和job
这两个key
;
调用的时候可以这样调用:
>>> person('jack',24,city='beijing',job='engineer')
jack 24 beijing engineer
那么我们多传或者少传参数呢?就会报错,如下:
>>> person('sun',33, city="beijing",job="actor",alive="yes")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: person() got an unexpected keyword argument 'alive'
>>> person('jack',24,city='beijing')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: person() missing 1 required keyword-only argument: 'job'
注意:这个方法只有python3.0以上的才支持,python2.x是不支持的,下面这个就是在python2.7中验证,结果报错了:
>>> def person(name, age,*,city,job):
SyntaxError: invalid syntax
如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*
了:
def person(name, age, *args, city, job):
print(name, age, args, city, job)
命名关键字参数可以有缺省值,从而简化调用:
def person(name, age, *, city='Beijing', job):
print(name, age, city, job)
这样也可以不用传入city
,如:
>>> person('Jack', 24, job='Engineer')
Jack 24 Beijing Engineer
5、参数组合
在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可选参数、命名关键字参数(python2.x无)和关键字参数。
比如定义一个函数,包含上述若干种参数:
def f1(a, b, c=0, *args, **kw):
print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
def f2(a, b, c=0, *, d, **kw):
print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
在函数调用的时候,Python解释器自动按照参数位置和参数名把对应的参数传进去。
>>> f1(1, 2)
a = 1 b = 2 c = 0 args = () kw = {}
>>> f1(1, 2, c=3)
a = 1 b = 2 c = 3 args = () kw = {}
>>> f1(1, 2, 3, 'a', 'b')
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
>>> f1(1, 2, 3, 'a', 'b', x=99)
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
>>> f2(1, 2, d=99, ext=None)
a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}
最神奇的是通过一个tuple和dict,你也可以调用上述函数:
>>> args = (1, 2, 3, 4)
>>> kw = {'d': 99, 'x': '#'}
>>> f1(*args, **kw)
a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}
>>> args = (1, 2, 3)
>>> kw = {'d': 88, 'x': '#'}
>>> f2(*args, **kw)
a = 1 b = 2 c = 3 d = 88 kw = {'x': '#'}
参考文档:http://www.runoob.com/manual/pythontutorial/docs/html/controlflow.html#tut-if
https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431752945034eb82ac80a3e64b9bb4929b16eeed1eb9000