forked from xingkeyu/byte_of_python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path09-functions.pd
378 lines (247 loc) · 13.4 KB
/
09-functions.pd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
# 函数
函数是重用的程序片段。它们允许你给一块语句一个名字,允许您在你的程序的任何地方使用指定的名字运行任何次数。这就是所谓的*函数*调用。我们已经使用了许多内置函数, 如`len`和`range`。
函数概念可能是任何有价值软件中*最*重要的块(在任何编程语言中),所以,在这一章,我们将探索函数的各各方面。
定义函数使用`def`关键字。在这个关键字之后是*标识*函数的名字,其次是在一对括号中可以附上一些变量名,最后在行的末尾是冒号。接下来是语句块--函数的一部分。一个例子将展示这些,这实际上是非常简单的:
例子 (保存为`function1.py`):
~~~python
def sayHello():
print('世界您好!') # 属于函数的块
# End of function
sayHello() # 调用函数
sayHello() # 再次调用函数
~~~
输出:
~~~
$ python3 function1.py
世界您好!
世界您好!
~~~
它是如何工作的:
我们使用上述的语法,定义了一个称为`sayHello`函数。这个函数没有参数,因此没有在圆括号中声明变量。函数的参数只是输入到函数中,以便我们可以给它传递不同的值返回相应的结果。
注意,我们可以调用相同的函数两次,这意味着我们不需要再写同样的代码。
## 函数的参数
一个函数可以带参数--你提供给函数的值,利用这些值该函数可以*做*一些事情。这些参数就像变量除了当我们调用函数时这些变量的值已经被定义,当函数运行时,它们已经有了指定的的值。
参数是在函数定义中在一对括号中指定,之间用逗号分隔。当我们调用这个函数,我们以同样的方式提供这些值。注意使用的术语——在函数的定义中给出的名字叫*形参*,而在函数调用时您提供的值被称为*实参*。
例子 (保存为`func_param.py`):
~~~python
def printMax(a, b):
if a > b:
print(a, '大')
elif a == b:
print(a, '等于', b)
else:
print(b, '大')
printMax(3, 4) # 直接给出字面值
x = 5
y = 7
printMax(x, y) # 给出参数的变量
~~~
输出:
~~~
$ python3 func_param.py
4 大
7 大
~~~
它如何工作的:
在这里,我们定义了一个称为`printMax`的函数,它使用叫做`a`和`b`的两个参数。我们使用简单的`if..else`语句找出比较大的数,然后打印较大的数。
我们第一次调用函数`printMax`,我们直接提供了数字作为参数。在第二种情况下,我们调用函数使用变量作为参数。`printMax`把实参`x`分配给形参`a`,`y`分配给`b`。在这两种情况下,printMax函数以同样方式工作。
## 局部变量
你在函数定义中声明的变量,他们与在函数外使用的其它同名变量没有任何关系,即变量名称对函数来说是*局部*的。这叫变量的*范围*。所有变量都有它们被声明的块的范围,从名称定义的点开始。
例子 (保存为`func_local.py`):
~~~python
x = 50
def func(x):
print('x等于', x)
x = 2
print('局部变量x改变为', x)
func(x)
print('x一直是', x)
~~~
输出:
~~~
$ python3 func_local.py
x等于50
局部变量x改变为2
x一直是50
~~~
它是如何工作的:
第一次,我们使用函数体中第一行打印变量*x*的*值*,Python使用在主块中,函数定义上声明的实参。
接下来,我们给`x`赋值为`2`,变量为`x`对我们的函数来说是局部变量,因此在函数中当我们改变`x`的值时,在主块中定义的变量`x`不受影响。
最后调用的`print`函数,显示在主块中定义的变量`x`,因此证实,它不受在前面调用函数的局部变量的影响。
## 使用全局声明
如果你想给在顶层的程序(即未在任何类型的范围如函数或类之中)定义的变量赋值,那么你必须告诉Python,变量不是局部的,而是*全局*的。我们使用`global`语句,没有`global`语句赋值给一个在函数外定义的变量是不可能的。
您可以使用这些在函数外定义的变量的值(假设在函数内没有同名的变量)。然而,这并不鼓励,应该避免,因为这使程序的读者不清楚变量是在哪里定义的,使用 `global` 语句就非常清楚,变量定义在一个最外的块中。
例子 (保存为`func_global.py`):
~~~python
x = 50
def func():
global x
print('x的值是', x)
x = 2
print('全局变量x改为', x)
func()
print('x的值是', x)
~~~
输出:
~~~
$ python3 func_global.py
x的值是50
全局变量to改为2
x的值是2
~~~
它是如何工作的:
`global`语句用来声明`x`是全局变量,当我们在函数内给`x`赋值时,它的改变映射到我们在主块中使用的`x`的值。
用同样的`global`语句可以指定多个全局变量,比如: `global x, y, z`。
## 默认参数
对于一些函数,你可能想要一些参数是*可选*,即在用户不希望为它们提供值时使用默认值,这在默认的参数值的帮助下完成的。你可以在函数定义中通过在参数名称后使用赋值操作符(`=`)后跟默认值来指定默认的参数值。
注意,默认参数值应该是一个常数。更准确的说,默认的参数值应该是不可变的——这在后面的章节中做了详细解释。现在,只要记住这点。
例子 (保存为 `func_default.py`):
~~~python
def say(message, times = 1):
print(message * times)
say('你好')
say('世界', 5)
~~~
输出:
~~~
$ python3 func_default.py
你好
世界世界世界世界世界
~~~
它是如何工作的:
函数`say`是用来按照指定的次数打印一个字符串。如果我们不提供一个值,那么在默认情况下字符串只打印一次。为此,我们为参数`times`指定一个默认参数值`1`。
在第一次使用函数`say`时,我们只提供了字符串,它打印字符串一次。在第二次使用`say`时,我们提供了字符串和一个实参`5`两个参数,说明我们想要*say*字符串5次。
重要一点
: 只有在参数列表后面的的参数可以被赋予默认参数值,即在参数列表中,你不能在没有默认值的参数前有有默认参数值的参数。
这是因为,值按位置分配给参数。例如,`def func(a, b=5)`是有效的,而`def func(a=5, b)`是*无效*的。
## 参数关键字
如果你有一些有许多参数的函数,您想要指定参数中的一些,那么,你可以通过为参数命名来为它们赋值——这叫做*参数关键字*——我们使用名称(关键字)而不是位置(我们一直使用的)来指定函数的参数。
这有两个*优势*,一是,使用函数容易,因为我们不需要担心参数的顺序。二是,如果其他参数有默认参数值,我们可以只给我们想赋值的参数赋值。
例子 (保存为`func_key.py`):
~~~python
def func(a, b=5, c=10):
print('a为', a, '和b为', b, '和c为', c)
func(3, 7)
func(25, c=24)
func(c=50, a=100)
~~~
输出:
~~~
$ python3 func_key.py
a为3 和b为7 和c为10
a为25 和b为5 和c为24
a为100 和b为5 和c为50
~~~
它是如何工作的:
名为`func`的函数中有一个参数没有默认参数值,后面两个参数有默认参数值。
第一次使用`func(3, 7)`,参数`a`得到值`3`,参数`b`得到值`7`,参数`c`得到默认值`10`。
第二次使用`func(25, c=24)`, 参数`a`按照参数的位置得到值`25`,然后参数`c`按照参数名,也就是参数关键字,得到值`24`,变量`b`得到默认值`5`。
第三次使用`func(c=50, a=100)`,我们为所有给定的值使用了参数关键字。注意,我们为参数`c`指定值是在参数`a`之前,尽管在函数定义中`a`在`c`前。
## 变量参数
有时你可能想定义一个函数,它可以获取参数的*任何*值,这可以通过使用星号(另存为`total.py`)实现:
~~~python
def total(initial=5, *numbers, **keywords):
count = initial
for number in numbers:
count += number
for key in keywords:
count += keywords[key]
return count
print(total(10, 1, 2, 3, vegetables=50, fruits=100))
~~~
输出:
~~~
$ python3 total.py
166
~~~
它是如何工作的:
当我们声明一个星号的参数,如`*param`,那么从这一点开始到结束的所有位置的参数都被收集到一个叫`param`的元组中。
同样,当我们声明一个双星参数,如`**param`,那么人那一点开始到结束的所有关键字参数都被收集到一个叫`param`的字典中。
我们将在[后面章节)(#数据结构)中探讨元组和字典。
## 只有关键字的参数
如果我们想要指定特定的关键字参数作为只有关键字的参数,而*不*是位置参数,它们可以被声明在星号参数后(另存为`keyword_only.py`):
~~~python
def total(initial=5, *numbers, extra_number):
count = initial
for number in numbers:
count += number
count += extra_number
print(count)
total(10, 1, 2, 3, extra_number=50)
total(10, 1, 2, 3)
# Raises error because we have not supplied a default argument value for 'extra_number'
~~~
输出:
~~~
$ python3 keyword_only.py
66
Traceback (most recent call last):
File "keyword_only.py", line 12, in <module>
total(10, 1, 2, 3)
TypeError: total() needs keyword-only argument extra_number
~~~
它是如何工作的:
在星号参数后面声明参数,结果是只有关键字参数,如果这些参数没有提供一个默认值,那么如果关键字参数没有提供值,函数调用会产生错误,如上所示。
注意,`+=`的用法是操作符的缩写,因此,`x = x + y`,你可以写成`x += y`。
如果你不需要星号参数,但还想使用只有关键字参数,那么只需简单使用一个星号而不使用任何名字,例如,`def total(initial=5, *, extra_number)`。
## return语句
`return` 语句用来从函数中*return(返回)*,也就是说跳出函数。同样,我们也可以从函数中选择性地*返回一个值*。
例子 (保存为`func_return.py`):
~~~python
def maximum(x, y):
if x > y:
return x
elif x == y:
return '两个数相等'
else:
return y
print(maximum(2, 3))
~~~
输出:
~~~
$ python3 func_return.py
3
~~~
它是如何工作的:
函数`maximum`返回参数中的最大值,在这个例子中是提供给函数的数值。它使用了简单的`if..else`语句找到比较大的值,然后*return(返回)*那个值。
注意,没有一个值的`return`语句相当于`return None(什么也不返回)`。`None`是Python中的一个特殊类型,它代表什么也没有。例如,如果一个变量的值是`None`,它说明这个变量没有值。
除非你已经写了自己的`return`语句,否则,每个函数都默认包含一个`return None`语句。通过运行`print(someFunction())`你可以看到这一点,这里`someFunction` 没有使用`return`语句,比如:
~~~python
def someFunction():
pass
~~~
在Python中`pass`语句用来说明一个空的语句块。
注意
: 已经有一个叫`max`的内建函数能够完成'find maximum'函数的功能 ,因此,只要可能使用这个内建函数。
## 文档字符串
Python有一个叫*documentation strings(文档字符串)*的好特性,通常用缩写名*docstrings*来指定。 文档字符串是你应该使用的一个重要工具,它对程序文档有助,令其容易理解。令人惊讶的是,当程序实际运行时,我们甚至可以从例如一个函数返回文档字符串。
例子 (保存为`func_doc.py`):
~~~python
def printMax(x, y):
'''打印两个数中的最大值。
两个值必须是整数。'''
x = int(x) # 如果可能,转换为整数
y = int(y)
if x > y:
print(x, '最大')
else:
print(y, '最大')
printMax(3, 5)
print(printMax.__doc__)
~~~
输出:
~~~
$ python3 func_doc.py
5 最大
打印两个数中的最大值。
两个值必须是整数。
~~~
它是如何工作的:
函数的第一个逻辑行的字符串是那个函数的*文档字符串*。注意,文档字符串也适用于在各自 的章节将要学习的[模块](#模块)和(类)(#面向对象的程序设计)。
文档的以贯例是多行字符串,第一行以大写字母开头以句点(.)结束(注:中文在V3.3中也可以),第二行是空行,从第三行开始是详细描述。*强烈建议*,为你重要的函数写文档字符串要遵循此贯例。
我们可以使用函数的`__doc__`(注意,**双下划线**)属性(属于名字的)访问`printMax`函数的文档字符串。只要记住,Python把*一切任何事情*作为一个对象对待,这也包括函数。我们将在[类](#面向对象编程)这一章学习关于对象的更多知识。
如果你在Python中已经使用过`help()`,那么你已经看到如何使用文档字符串了!它所做的仅仅是获取函数的 `__doc__` 属性,并以一个整洁的方式显示给你。你可以在上面的函数——在你的程序中仅包括`help(printMax)`尝试一下。记得按下`q`键,退出`help`。
自动化工具可以从你的程序中以这种方式检索文档。因此,我*强烈建议*,为你写的任何重要函数使用文档字符串。来自Python的自动化工具`pydoc`命令使用文档字符串的工作原理类似于`help()`。
## 小结
我们已经见过函数的很多方面,但请注意,我们仍然没有覆盖它们的所有方面。然而,我们已经覆盖了Python函数日常使用的大部分。
接下来,我们将看到如何创建及使用Python模块。