函数
# q" E3 y5 [) O$ ^4 C6 O) e, y, k! `; M7 a2 Z) s# x# G
简介& }- C, O' M1 F+ t" {, M
函数是重用的程序段。它们允许你给一块语句一个名称,然后你可以在你的程序的任何地方使用这个名称任意多次地运行这个语句块。这被称为 调用 函数。我们已经使用了许多内建的函数,比如 len 和 range。
: @3 [9 y5 ^8 a$ x2 V5 b0 [: N& |' v+ G" A& c# f
函数通过 def 关键字定义。def 关键字后跟一个函数的 标识符 名称,然后跟一对圆括号。圆括号之中可以包括一些变量名,该行以冒号结尾。接下来是一块语句,它们是函数体。下面这个例子将说明这事实上是十分简单的:' Q; L" n# v* \6 y. v5 ]
2 a; C; W4 y! C+ P
定义函数7 o# M" T+ n) [* E9 ?0 W
" o* w3 F4 v5 w: Z. b) O# r例 7.1 定义函数
' d8 P5 t7 ?, i: ] B/ C! x4 x; m- y& Y A1 Y+ h( [4 K
- #!/usr/bin/python # Filename: function1.py def sayHello(): print 'Hello World!' # block belonging to the function sayHello() # call the function
复制代码 + D4 [% I+ q0 l1 i& }( c
输出
1 X$ d r7 g) [& Y% O8 W( n/ ^1 x# K. c, }) y/ d
- $ python function1.py Hello World!
复制代码 1 {2 e; o; W- s; M! }5 f
它如何工作) y, H, X, P0 B" n# N: q
" s) Z, H l9 Q! ], h
我们使用上面解释的语法定义了一个称为 sayHello 的函数。这个函数不使用任何参数,因此在圆括号中没有声明任何变量。参数对于函数而言,只是给函数的输入,以便于我们可以传递不同的值给函数,然后得到相应的结果。" _- p) H# _" j* h: g/ x
. o& n9 N4 c7 b! O, \1 _
函数形参3 l1 @' \1 n) X/ J' t M+ G
5 l$ W5 o6 p; Q, P
函数取得的参数是你提供给函数的值,这样函数就可以利用这些值 做 一些事情。这些参数就像变量一样,只不过它们的值是在我们调用函数的时候定义的,而非在函数本身内赋值。; j$ g% _1 Y8 z6 n
6 n% ]# u; V, [( I参数在函数定义的圆括号对内指定,用逗号分割。当我们调用函数的时候,我们以同样的方式提供值。注意我们使用过的术语——函数中的参数名称为 形参 而你提供给函数调用的值称为 实参 。; c- ^! \) J4 N9 j
* q5 S/ k1 E8 S( {- x
使用函数形参- Z* I, m. m4 A8 h) K6 ^
: l- R5 m8 V( j$ D) n2 X
例 7.2 使用函数形参
" O2 ]3 z5 x1 w# Q1 g4 n2 M, `; B; z7 F- I5 _2 `3 ]& S7 c
- #!/usr/bin/python # Filename: func_param.py def printMax(a, b): if a > b: print a, 'is maximum' else: print b, 'is maximum' printMax(3, 4) # directly give literal values x = 5 y = 7 printMax(x, y) # give variables as arguments
复制代码 0 i3 L O8 d+ Y' g7 L' z1 D
输出
0 d! q. b. n4 G$ y; d" m; m# H' W0 F, @/ d8 v2 j% i3 q! s. p/ D
- $ python func_param.py 4 is maximum 7 is maximum
复制代码 " o2 j( j$ c4 j. U
& z: u' C5 l+ ?) N
它如何工作
5 y4 P$ Q9 R @' r9 Z" f- h% \
; f+ J' M; G5 P+ D这里,我们定义了一个称为 printMax 的函数,这个函数需要两个形参,叫做 a 和 b。我们使用 if..else 语句找出两者之中较大的一个数,并且打印较大的那个数。
0 H N6 z, h( f1 s% _& Q& M1 R; D" A: O
在第一个 printMax 使用中,我们直接把数,即实参,提供给函数。在第二个使用中,我们使用变量调用函数。printMax(x, y)使实参 x 的值赋给形参 a,实参y的值赋给形参 b。在两次调用中,printMax 函数的工作完全相同。% O" }8 S0 k4 J" Y6 J0 G* T+ J0 g
0 @$ k+ `! Y' O局部变量' r* x; ]/ Y2 y5 _6 T0 |
5 H& E _/ Y m5 X8 K+ n
当你在函数定义内声明变量的时候,它们与函数外具有相同名称的其他变量没有任何关系,即变量名称对于函数来说是 局部 的。这称为变量的 作用域 。所有变量的作用域是它们被定义的块,从它们的名称被定义的那点开始。
) J* g% C+ e" q. f7 k# {( X A6 r, b5 s0 w
使用局部变量
6 }5 D3 f+ |# h1 f
; l8 L' A7 Z3 t: P( L例 7.3 使用局部变量* c' R; T% g2 c
( i; y( V5 k: i; A3 L, v/ n% i
- #!/usr/bin/python # Filename: func_local.py def func(x): print 'x is', x x = 2 print 'Changed local x to', x x = 50 func(x) print 'x is still', x
复制代码
4 ?! e: l4 W8 m" F% e1 W, l输出
0 J1 A& R* S6 w' @& B- Z- $ python func_local.py x is 50 Changed local x to 2 x is still 50
复制代码
+ [0 w% U! D2 T它如何工作
& @* q! x( Q6 i" |) f/ ~' e# ?. @
4 f1 A& q. s6 q q6 _在函数中,我们第一次使用 x 的 值 的时候,Python 使用函数声明的形参的值。
( n9 |7 E( _. }
: k& |! O" {# R接下来,我们把值 2 赋给 x。x 是函数的局部变量。所以,当我们在函数内改变 x 的值的时候,在主块中定义的 x 不受影响。
1 O3 {' u0 W* K8 ]$ L& X
: D* |/ E1 d8 K# Q4 A% Q在最后一个 print 语句中,我们证明了主块中的 x 的值确实没有受到影响。6 f% Q! u" N! z
8 q$ ]' t2 e1 q. V0 v
使用 global 语句
# D/ m. A2 {9 Z% V! a
* x& }# z }) f& d/ e4 j# q% h如果你想要为一个定义在函数外的变量赋值,那么你就得告诉 Python 这个变量名不是局部的,而是 全局 的。我们使用 global 语句完成这一功能。没有 global 语句,是不可能为定义在函数外的变量赋值的。
. w, F$ S* k0 @0 ~/ e7 J G- u1 ?' @% O5 r8 M
你可以使用定义在函数外的变量的值(假设在函数内没有同名的变量)。然而,我并不鼓励你这样做,并且你应该尽量避免这样做,因为这使得程序的读者会不清楚这个变量是在哪里定义的。使用 global 语句可以清楚地表明变量是在外面的块定义的。' ~0 m) B5 I! G, e! x$ m( a; x8 E
6 y2 e" H% p8 c. ?例 7.4 使用 global 语句
# N1 |: D: {% W+ ^9 r; c1 `! C
) [# l; x g" L! y m- #!/usr/bin/python # Filename: func_global.py def func(): global x print 'x is', x x = 2 print 'Changed local x to', x x = 50 func() print 'Value of x is', x
复制代码
1 [/ g0 P6 R0 o$ d) }输出 g5 n& @" h" W4 v1 z4 G2 Q
- $ python func_global.py x is 50 Changed global x to 2 Value of x is 2
复制代码 , u" F! R' Q! z0 j- y+ j8 W! Q
它如何工作 t" I8 x! r2 L9 V( R
7 e& S7 g% x2 s7 G0 v7 J" {: Wglobal 语句被用来声明x是全局的——因此,当我们在函数内把值赋给x的时候,这个变化也反映在我们在主块中使用 x 的值的时候。' M) ^& U7 q! @! m- S
+ u1 p! U1 t- a, [' Z. C, c你可以使用同一个 global 语句指定多个全局变量。例如 global x, y, z。5 Z5 p2 S( U' _& n# p9 j4 L! M2 c
/ s/ [1 h' V& U/ R: ^默认参数值
8 B+ b) _8 W! F
1 g! v3 j/ ]0 N1 V. A对于一些函数,你可能希望它的一些参数是 可选的,如果用户不想要为这些参数提供值的话,这些参数就使用默认值。这个功能借助于默认参数值完成。你可以在函数定义的形参名后加上赋值运算符(=)和默认值,从而给形参指定默认参数值。 H7 Z3 b4 @ F, J# k% l( ?
S" {' I, h- T+ r* b+ K1 x
注意,默认参数值应该是一个参数。更加准确的说,默认参数值应该是不可变的——这会在后面的章节中做详细解释。从现在开始,请记住这一点。
G( k% P' w- G
; c, J* C2 n/ P1 F4 k7 E; y) F& O( @4 p使用默认参数值
, U8 }; s4 k1 k/ W8 m' s: a" h5 P2 A! G! b5 v s) t% W
例 7.5 使用默认参数值
' ]6 c; T3 e: K! z* X
% K t/ T: \2 T- o3 |. c- #!/usr/bin/python # Filename: func_default.py def say(message, times = 1): print message * times say('Hello') say('World', 5)
复制代码
5 M* f1 L; u% Y: \4 H0 _9 ~9 F输出
- O2 i: k* R: q# h- N' |. E* o! W, x
- $ python func_default.py Hello WorldWorldWorldWorldWorld
复制代码 % X) [6 {4 J+ t
它如何工作
4 i: R; e2 I8 Q6 I m0 e P1 S# S1 v* R8 G5 V# m# L
名为 say 的函数用来打印一个字符串任意所需的次数。如果我们不提供一个值,那么默认地,字符串将只被打印一遍。我们通过给形参 times 指定默认参数值1来实现这一功能。
+ g- F# x% X3 u% g' {- [# t$ W1 N
8 D5 { \( C6 K; \3 v I7 M在第一次使用 say 的时候,我们只提供一个字符串,函数只打印一次字符串。在第二次使用 say 的时候,我们提供了字符串和参数 5,表明我们想要 说 这个字符串消息 5 遍。
1 t% C! K1 }+ q. d% z. |) L: t: I) x2 ~
重要 只有在形参表末尾的那些参数可以有默认参数值,即你不能在声明函数形参的时候,先声明有默认值的形参而后声明没有默认值的形参。 这是因为赋给形参的值是根据位置而赋值的。例如,def func(a, b=5)是有效的,但是 def func(a=5, b)是 无效 的。
6 x: D$ N. r" D" f$ R( o# N- Q- E" S: B( v) e2 K
关键参数
: j& Y( F4 n( j7 ^6 E7 i+ a+ Z% r: c' V/ F6 b
如果你的某个函数有许多参数,而你只想指定其中的一部分,那么你可以通过命名来为这些参数赋值——这被称作 关键参数 ——我们使用名字(关键字)而不是位置(我们前面所一直使用的方法)来给函数指定实参。4 |% P' [' J4 H7 ~1 z
5 Y: x# z5 i @0 d这样做有两个 优势 ——一,由于我们不必担心参数的顺序,使用函数变得更加简单了。二、假设其他参数都有默认值,我们可以只给我们想要的那些参数赋值。3 |( D0 c/ v' _6 n4 ^
+ E2 ~" i4 C/ ~( k2 S
使用关键参数
5 _# x7 B, [. J: Q% U1 ~/ M' o$ Q( p9 w" B. Y
例 7.6 使用关键参数0 p" s1 ^% M& ~. e5 U5 l: G5 [4 R
- #!/usr/bin/python # Filename: func_key.py def func(a, b=5, c=10): print 'a is', a, 'and b is', b, 'and c is', c func(3, 7) func(25, c=24) func(c=50, a=100)
, B, d' I2 E( x0 s' w3 b
复制代码
& k3 o N$ \) o& q9 h输出
; j- `! G# n0 `# }0 ~7 N0 g+ L( c; }: @9 a! V. n
- $ python func_key.py a is 3 and b is 7 and c is 10 a is 25 and b is 5 and c is 24 a is 100 and b is 5 and c is 50
复制代码 # D( {6 f0 c$ s$ P2 s2 p' @( Y( h
它如何工作: q/ X: d* f' } v6 D( c0 W6 U/ r
- d% C4 n8 ]4 Z
名为 func 的函数有一个没有默认值的参数,和两个有默认值的参数。
" T V1 `7 y3 \3 X4 _; \( ~- b: H; g$ C6 D" C
在第一次使用函数的时候, func(3, 7),参数 a 得到值 3,参数 b 得到值 7,而参数 c 使用默认值 10。( L5 k5 l$ [, p
/ ?* [" a$ {) Z5 f M
在第二次使用函数 func(25, c=24)的时候,根据实参的位置变量 a 得到值 25。根据命名,即关键参数,参数 c 得到值 24。变量 b 根据默认值,为 5。
* @1 i3 v1 b7 r w ?3 n) H t W* C9 C, v+ E* L
在第三次使用 func(c=50, a=100)的时候,我们使用关键参数来完全指定参数值。注意,尽管函数定义中,a 在 c 之前定义,我们仍然可以在 a 之前指定参数 c 的值。+ D" [( Y2 P: }' G- w" A! b
1 ?+ f* V4 V) ~% B# D% F/ L5 E
return 语句4 Y. Q. k5 f1 O" n+ Z" O+ N$ |- ~. H
1 I" N! j+ z2 K* p$ T# breturn 语句用来从一个函数 返回 即跳出函数。我们也可选从函数 返回一个值 。
4 ^3 M3 u3 | K8 ^3 z1 y) p. V1 E0 s4 C6 M- b* ?+ {
使用字面意义上的语句
0 E/ g% |4 H2 V; q. {: l
9 i; x+ s' {6 b& m) P例 7.7 使用字面意义上的语句
$ C& g7 a$ m7 m3 o+ e1 ^1 V8 }( L# o! z
- #!/usr/bin/python # Filename: func_return.py def maximum(x, y): if x > y: return x else: return y print maximum(2, 3)
复制代码
' R- r. t1 t! v) @
( i1 p. f# `0 j1 P' w输出
+ ^3 F6 H7 ]4 S
! O4 Q$ O* o P2 ]& R- $ python func_return.py 3
复制代码
+ v3 m/ D" h; J+ C' v7 M9 @) l它如何工作: V: I) K4 n6 o- R9 e
. e! H- }* N B4 Tmaximum 函数返回参数中的最大值,在这里是提供给函数的数。它使用简单的 if..else 语句来找出较大的值,然后 返回 那个值。
9 v. I% C2 K& f
+ o8 ^5 s U* W, g e0 b, P注意,没有返回值的 return 语句等价于 return None。None 是 Python 中表示没有任何东西的特殊类型。例如,如果一个变量的值为 None,可以表示它没有值。
5 w' Q, F6 K; M% i
" O3 T# [. T7 m+ n Z) R; _除非你提供你自己的 return 语句,每个函数都在结尾暗含有 return None 语句。通过运行 print someFunction(),你可以明白这一点,函数 someFunction 没有使用 return 语句,如同:' T ?2 ?& G1 a
6 I5 U: {, V+ a2 {, Y* _2 |$ ]5 l; z: }" K; X6 U
8 Z3 H* q( u# N% N% Z$ W, ^" | F
pass 语句在 Python 中表示一个空的语句块。
% Z% F" k' u, J- l" p5 l2 Z, L- [' F" a! c# N% D
DocStrings* g) [% }( c% |. |
9 e t* L" ~8 B- Q$ e6 Q. vPython 有一个很奇妙的特性,称为 文档字符串,它通常被简称为 docstrings 。DocStrings 是一个重要的工具,由于它帮助你的程序文档更加简单易懂,你应该尽量使用它。你甚至可以在程序运行的时候,从函数恢复文档字符串!
* G) o0 U5 e8 _1 E4 L/ }
1 `$ A& ]( Q% ^) {使用 DocStrings
6 e! u9 l+ P$ d( T+ \! h D7 }+ O: } E1 r- m$ A
例 7.8 使用 DocStrings
0 `" M/ {3 U2 o" D
6 y% K: \6 @- r2 y4 A$ _- #!/usr/bin/python # Filename: func_doc.py def printMax(x, y): '''Prints the maximum of two numbers. The two values must be integers.''' x = int(x) # convert to integers, if possible y = int(y) if x > y: print x, 'is maximum' else: print y, 'is maximum' printMax(3, 5) print printMax.__doc__
复制代码
v- U* ]! f! W1 P) Y; A输出7 l Q- @- n+ s3 m( T# ~/ ~
[3 E! ?7 O4 C" q9 z
- $ python func_doc.py 5 is maximum Prints the maximum of two numbers. The two values must be integers.
复制代码 " H2 m8 P, O5 }/ i h
它如何工作
/ H/ C6 r+ D+ h1 M$ a- H! s, i/ B4 V/ S( ^
在函数的第一个逻辑行的字符串是这个函数的 文档字符串 。注意,DocStrings 也适用于模块和类,我们会在后面相应的章节学习它们。
+ G1 w7 s$ |7 M4 U+ ]. l5 M* |
# k0 [# H+ M3 g, H0 s文档字符串的惯例是一个多行字符串,它的首行以大写字母开始,句号结尾。第二行是空行,从第三行开始是详细的描述。 强烈建议 你在你的函数中使用文档字符串时遵循这个惯例。
: v2 u1 s8 i( n
& a! D2 z' J. K% C6 @% C# |你可以使用 doc (注意双下划线)调用 printMax 函数的文档字符串属性(属于函数的名称)。请记住 Python 把 每一样东西 都作为对象,包括这个函数。我们会在后面的类一章学习更多关于对象的知识。
1 E g4 E/ Q# [7 p( e: ]7 ]( _* W' V4 R# i' L2 x6 }8 {! J# x9 Y
如果你已经在 Python 中使用过 help(),那么你已经看到过 DocStings 的使用了!它所做的只是抓取函数的 doc 属性,然后整洁地展示给你。你可以对上面这个函数尝试一下——只是在你的程序中包括 help(printMax)。记住按 q 退出 help。
2 ]" t1 e7 }& u; Z- N* V. b
% ~$ ~& e" E/ h自动化工具也可以以同样的方式从你的程序中提取文档。因此,我 强烈建议 你对你所写的任何正式函数编写文档字符串。随你的 Python 发行版附带的 pydoc 命令,与 help()类似地使用 DocStrings。( D* J; w B# c6 G/ }
: w, @/ T& J7 ^- S, i概括
; ?: J2 u' G% o B+ _
! I6 W9 e8 V+ R6 F9 }0 t我们已经学习了函数的很多方面的知识,不过注意还有一些方面我们没有涉及。然而,我们已经覆盖了大多数在日常使用中,你可能用到的 Python 函数知识。+ L, p; |' h3 H- W. J+ G( g8 C
7 n! |% F: X- _- r
接下来,我们将学习如何创建和使用 Python 模块。
& o0 z( R/ L3 P$ |$ n$ w9 t
' S4 C/ c3 Y$ Q# U! Z |