1.懒惰是一种美德,减少代码冗余量
如果要编写大型程序,你很快就会遇到麻烦。想想看,如果你在一个地方编写了一些代码,但需要在另一个地方再次使用,该如何办呢?例如,假设你编写了一段代码,它计算一些斐波那契数(一种数列,其中每个数都是前两个数的和)。
fibs = [0, 1]
fori in range(8):
fibs.append(fibs[-2] + fibs[-1])
运行上述代码后,fibs将包含前10个斐波那契数。
>>> fibs
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
如果你想一次计算前10个斐波那契数,上述代码刚好能满足需求。你甚至可以修改前述for循环,使其处理动态的范围,即让用户指定最终要得到的序列的长度。
fibs = [0, 1]
num = int(input('How many Fibonacci numbers do you want? '))
fori in range(num-2):
fibs.append(fibs[-2] + fibs[-1])
print(fibs)
如果要使用这些数字做其他事情,该如何办呢?当然,你可以在需要时再次编写这个循环,但如果已编写好的代码更复杂呢(如下载一组网页并计算所有单词的使用频率)?在这种情况下,你还愿意多次编写这些代码吗(每当需要时就编写一次)?不,真正的程序员是不会这样做的。真正的程序员很懒。这里说的懒不是贬义词,而是说不做无谓的工作。
那么真正的程序员会如何做呢?让程序更抽象。要让前面的程序更抽象,可以像下面这样做:
num = input('How many numbers do you want? ')
print(fibs(num))
在这里,只具体地编写了这个程序独特的部分(读取数字并打印结果)。实际上,斐波那契数的计算是以抽象的方式完成的:你只是让计算机这样做,而没有具体地告诉它如何做。你创建了一个名为fibs的函数,并在需要计算斐波那契数时调用它。如果需要在多个地方计算斐波那契数,这样做可节省很多精力。
2.抽象和结构
抽象可节省人力,但实际上还有个更重要的优点:抽象是程序能够被人理解的关键所在(无论对编写程序还是阅读程序来说,这都至关重要)。计算机本身喜欢具体而明确的指令,但人通常不是这样的。例如,如果你向人打听怎么去电影院,就不希望对方回答:“向前走10步,向左转90度,接着走5步,再向右转45度,然后走123步。”听到这样的回答,你肯定一头雾水。
如果对方回答:“沿这条街往前走,看到过街天桥后走到马路对面,电影院就在你左边。”你肯定能明白。这里的关键是你知道如何沿街往前走,也知道如何过天桥,因此不需要有关这些方面的具体说明。
组织计算机程序时,你也采取类似的方式。程序应非常抽象,如下载网页、计算使用频率、打印每个单词的使用频率。这很容易理解。下面就将前述简单描述转换为一个Python程序。
page = download_page()
freqs = compute_frequencies(page)
for word, freq in freqs:
print(word, freq)
看到这些代码,任何人都知道这个程序是做什么的。然而,至于具体该如何做,你未置一词。你只是让计算机去下载网页并计算使用频率,至于这些操作的具体细节,将在其他地方(独立的函数定义)中给出。
3.自定义函数
函数执行特定的操作并返回一个值,但实际上,在Python中并非所有的函数都返回值,你可以调用它(调用时可能需要提供一些参数——放在圆括号中的内容)。一般而言,要判断某个对象是否可调用,可使用内置函数callable。
>>> import math
>>> x = 1 ··
>>> y = math.sqrt
>>> callable(x)
False
>>> callable(y)
True
前一节说过,函数是结构化编程的核心。那么如何定义函数呢?使用def(表示定义函数)语句。
def hello(name):
return 'Hello, ' + name + '!'
运行这些代码后,将有一个名为hello的新函数。它返回一个字符串,其中包含向唯一参数指定的人发出的问候语。你可像使用内置函数那样使用这个函数。
>>> print(hello('world'))
Hello, world!
>>> print(hello('Gumby'))
Hello, Gumby!
很不错吧?如果编写一个函数,返回一个由斐波那契数组成的列表呢?很容易!只需使用前面介绍的代码,但不从用户那里读取数字,而是通过参数来获取。
def fibs(num):
result = [0, 1]
fori in range(num-2):
result.append(result[-2] + result[-1])
return result
执行这些代码后,解释器就知道如何计算斐波那契数了。现在你不用再关心这些细节,而只需调用函数fibs。
>>> fibs(10)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
>>> fibs(15)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]
在这个示例中,num和result也可以使用其他名字,但return语句非常重要。return语句用于从函数返回值(在前面的hello函数中,return语句的作用也是一样的)
4.给函数编写文档
要给函数编写文档,以确保其他人能够理解,可添加注释(以#打头的内容)。还有另一种编写注释的方式,就是添加独立的字符串。在有些地方,如def语句后面(以及模块和类的开头),添加这样的字符串很有用。放在函数开头的字符串称为文档字符串(docstring),将作为函数的一部分存储起来。下面的代码演示了如何给函数添加文档字符串:
def square(x):
'Calculates the square of the number x.'
return x * x
可以像下面这样访问文档字符串:
>>> square.__doc__
'Calculates the square of the number x.'
__doc__是函数的一个属性。属性名中的双下划线表示这是一个特殊的属性。
特殊的内置函数help很有用。在交互式解释器中,可使用它获取有关函数的信息,其中包含函数的文档字符串。
>>> help(square)
Help on function square in module __main__:
square(x)
Calculates the square of the number x.
5.其实并不是函数的函数
数学意义上的函数总是返回根据参数计算得到的结果。在Python中,有些函数什么都不返回。在Python中,函数就是函数,即使它严格来说并非函数。什么都不返回的函数不包含return语句,或者包含return语句,但没有在return后面指定值。
def test():
print('This is printed')
return
print('This is not')
这里使用return语句只是为了结束函数。
>>> x = test()
This is printed
如你所见,跳过了第二条print语句。(这有点像在循环中使用break,但跳出的是函数。)既然test什么都不返回,那么x指向的是什么呢?下面就来看看:
>>> x
>>>
什么都没有。再仔细地看看。
>>> print(x)
None
这是一个你熟悉的值:None。由此可知,所有的函数都返回值。如果你没有告诉它们该返回什么,将返回None。
不要让这种默认行为带来麻烦。如果你在if之类的语句中返回值,务必确保其他分支也返回值,以免在调用者期望函数返回一个序列时(举个例子),不小心返回了None。
本文介绍了Python编程中抽象和自定义函数的概念,强调了抽象在程序可读性和效率上的重要性。通过斐波那契数列的例子展示了如何通过函数实现代码的复用和抽象,同时讲解了函数的定义、调用以及返回值。还提到了函数的文档字符串和内置帮助函数`help()`,以提高代码的可读性。最后,讨论了即使不返回值的函数也会默认返回`None`的情况。
2万+

被折叠的 条评论
为什么被折叠?



