先写一个例子——生成n以内的Fibonacci数:
def
fib(n): a,b
=
0,
1
while
b
<
n:
print
b, a,b
=
b,a
+
b
def指出了接下来的部分是一个函数。Python和C语言类似,并不区分过程(无返回值)和函数(有返回值)。像上面那样严格的说就是一个过程(Procedure)。
对于一个项目而言,在不同的模块的代码中插入一段简洁明了的说明文字是很有必要的。Python支持类似Java-Doc的语法。例如:
def
fib(n
):
"""
Print a Fibonacci series up to n.
"""
a,b
=
0,
1
while
b
<
n:
print
b, a,b
=
b,a
+
b
将说明文字放在一对“”“(三个又引号)之间,一些文档生成工具就会将这些文字提取出来,生成HTML或是LaTeX等文档。写这些文字费不了多少时间,养成这种习惯绝对是大有好处的。
函数的调用也非常简单,对于上面的而言,只需直接用fib(100),就会产生相应的输出:
1 1 2 3 5 8 13 21 34 55 89
函数本身也可以被引用。对于已经定义好的fib来说,如果有一句:f=fib,就意味着f引用了fib这个函数。现在这两个名字所指的就是同一个东西。于是就可以这样使用:
>>>f(100)
输出结果和上面的是一样的。可以比照着C语言中的”函数指针“来理解一下。
虽然Python的函数可以不显式地写出return语句,实际上这种函数也会返回一个特殊的值None。例如有一个什么都不干的函数:
def
fun():
pass
可以通过在解释器中用print来显示一下它的值:
>>>print fun()
None
现在可以将上面的fib函数改造一下,让它不再直接产生输出,而是产生一个Fibonacci数列的List:
def
fib2(n):
"""
Print a Finonacci series up to n.
"""
a,b
=
0,
1
result
=
[]
while
b
<
n: result.append(b) a,b
=
b,a
+
b
return
result
append是List类的一个方法,即向一个List后添加元素。这个函数的效果如下:
>>>print fib2(100)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
默认参数
Python函数支持默认参数。你可以定义一个两个参数的函数,但在调用的时候可以只告诉其中一个参数或是一个都不告诉——只要你在定义的时候指定了参数的默认值。这很像是从C++中学来的。
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
这样就有了多种调用方式:
>>>ask_ok('Do you really want to quit?')
>>>ask_ok('Do you really want to quit?',2)
>>>ask_ok('Do you really want to quilt?',3,'What do you want to do?')
参数的默认值是在定义的时在函数的入口处确定下来的。这可以通过一个实验来说明:
i
=
5
def
f(arg
=
i):
print
arg i
=
6
f()
发现输出的是5而不是6,因为后来的i改变根本不会对函数里的arg造成影响。
要注意的是,函数的默认参数部分只会被计算一次。这样如果默认参数是某种复合类型(List,String,Class),可能会产生一种”积累效应“:
def
f(a,L
=
[]): L.append(a)
return
L
如果调用三次:
>>> print f(1)
[1]
>>> print f(2)
[1, 2]
>>> print f(3)
[1, 2, 3]
要避免这种情况,就需要在定义的参数列表中显式地将L的默认值指定为None:
def
f(a,L
=
None):
if
L
is
None: L
=
[] L.append(a)
return
L
带关键字的参数
关键字可以理解为函数头部参数的名字。通过在调用函数的时候指定关键字,可以不按照参数定义的顺序来传递参数的值。
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,
"
!
"
带关键字调用:
parrot(1000)
parrot(action = 'VOOOOOM', voltage = 1000000)
parrot('a thousand', state = 'pushing up the daisies')
parrot('a million', 'bereft of life', 'jump')
下面的几种调用方式是错的:
parrot() # 缺少指定参数
parrot(voltage=5.0, 'dead') # 没有指出关键字
parrot(110, voltage=220) # 传递重复参数
parrot(actor='John Cleese') #
不存在的关键字
更为灵活的是,可以通过在函数定义时用*name或**name的方式代表不确定的参数或带有关键字的参数(Dictionary)。这个用例子说明会容易理解一下:
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
=
keywords.keys() keys.sort()
for
kw
in
keys:
print
kw,
'
:
'
, keywords[kw]
可以这样调用:
cheeseshop('Limburger', "It's very runny, sir.","It's really very, VERY runny, sir.",client='John Cleese', shopkeeper='Michael Palin',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
传递多个参数时还可以通过List来进行。List中的元素会被分离开,称为Unpack,这是Python解释器在幕后完成的。例如range函数可以指定两个参数,可以把这两个参数构成一个List,再将这个List传入:
>>> args = [3, 6]
>>> range(*args) # call with arguments unpacked from a list
[3, 4, 5]
类似地,可以使用**操作符来传递一个字典,对应于带关键字传递参数的方式。
>>> def parrot(voltage, state='a stiff', action='voom'):
... print "-- This parrot wouldn't", action,
... print "if you put", voltage, "volts through it.",
... print "E's", state, "!"
...
>>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
>>> parrot(**d)
-- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !
用心领悟一下。
Lambda函数
Python从函数语言中学来了这一功能。Lambda函数是一种匿名函数,功能有些像函数的模板,通过它可能方便地生成其他函数。感觉Lambda函数更加需要领悟,只里仅仅记几个例子:
>>> def make_incrementor(n):
... return lambda x: x + n
...
>>> f = make_incrementor(42)
>>> f(0)
42
>>> f(1)
43