抽象——人类伟大之始
引言
抽象
可能是人类之所以为人的一个重要因素。
先来看一下辞典上对抽象
的定义:
抽象
是从众多的事物中抽取出共同的、本质性的特征,而舍弃其非本质的特征的过程。
抽象
的艺术弱化了具体
事物的描述,强调艺术的本质:表达人的感受;
抽象
的知识不会去描述具体
的事物,而是描述一类事物的共性和内涵。
在计算机领域,抽象
的思想,让人们不用去考虑一个功能的具体
细节,而是从更高的视角关注它的性质。
正常情况下,计算机科学中的抽象
需要联系面向对象编程
(Object-Oriented Programming
,或 OOP
) 讲解;但是由于它不是我们要求掌握的,所以我们尝试绕开 OOP
说明 抽象
的概念。
计算机科学中的抽象
要理解计算机中抽象
,我们要先说具体
。
首先,我们定义一个函数,可以将两个数组逐个元素相加,多出来的元素直接放在后面:
def add_lists(list1, list2):
length1 = len(list1)
length2 = len(list2) # 获得两个列表的长度
newList = [] # 创建一个新的空列表
i = 0
while i < min(length1, length2): # 循环到短的那个列表的长度为止
newList.append(list1[i] + list2[i]) # 两个列表的对应位置一定有元素,直接相加
i = i + 1
if length2 > length1: # 如果第二个列表更长,直接把第二个列表的剩余元素插进去
for i in range(length1, length2):
newList.append(list2[i])
else: # 不然的话,把第一个列表的剩余元素插进去
for i in range(length2, length1):
newList.append(list1[i])
return newList
这样的话,如果我们调用 add_list([1,2,3], [4,5,6,7])
,我们会得到 [5, 7, 9, 7]
。
一旦这个函数定义好,我们便将这个函数的实现细节遗忘。我们的脑海中,只剩下了这样的信息:
def add_lists(list1, list2):
# 输入两个 list
# 输出两个 list 的和
当我们要定义多个列表加法的时候,我们不是从头开始写,而是使用以上的信息,在之前的基础上进行:
def sum_lists(lists):
curr_list = []
for lst in lists:
curr_list = add_lists(curr_list, lst)
return curr_list
有一天,可能 add_lists
的实现方式改变了(比如用了效率更高的实现方式),但是只要它的使用方式没变,你就不需要做任何事情,也不需要关心它究竟作出了什么改变。
当然,实现完 sum_lists
之后,你也只需要留下下列信息:
def sum_lists(lists):
# 输入一个包含了多个数组的数组
# 输出所有数组的和
你可以把你写好的函数放到网上,供其他人使用(第三方库
本质上就是这样的东西)。读者大部分情况下也不需要知道函数的内容,他只要知道函数的输入输出(使用方法)就可以了。换言之,就是把它看作了一个黑箱
。这就是计算机科学中的抽象
。
关于抽象
的一些扯皮
以下是我被问过的一个问题:
我们现在做研究,一般需要精通一个领域内的所有知识之后,再有所贡献。比如,想研究量子物理,需要从基础的数学开始学起,到中学物理、大学物理和更高深的理论,一路走到人类知识的边界,之后才能去突破它。可是,人类现在一直在积累知识,那么会不会有一天,人穷进一生也学不完现有的领域内知识,于是科学的发展就停滞了?
我认为不会。人类的抽象
思维可以很好地解决这个问题。
当知识太多的时候,我们可以像之前 add_lists
的例子一样,把它们抽象出来。我们不用知道理论的每一个细节,只需要在更高的视角下知道它在整个体系中的作用即可。这样,知识的成本就被大大降低了。
抽象
构筑知识框架的同时,也提供了很自然的分工模式。理论的内容有可能出错,函数的实现方式可能需要优化,所以一定会有人重新去审视它们。人们可以把它们当作黑箱
,以它们为基础去突破科学的边界;也会有人专注于深究它们的内容,查看黑箱
的内部,进行反思和优化。
曾有位大佬说过,编程就是在书写和组织知识,我表示非常赞同。所以,我们要适时使用抽象
的思维,以减轻自己和代码读者的负担。