编程领域常说的一句话是不要重复造轮子,因此重用已有的代码是编程设计的重要思想。Python中有大量已经非常完善的类和函数,这些可以重用的类和函数称为模块。在Python中进行游戏编程开发依赖的模块是Pygame,这个模块将在第3章进行介绍。进行AI编程开发的模块是PyTorch,这个模块将在第8章进行介绍。我们还会依赖其他一些模块,对于这些模块我们在此做简单介绍。如果有需要,读者可以通过官网查阅更详细的模块资料。如果本地环境还没有安装这些模块,需要在联网条件下通过pip进行安装。
如名称的含义所示,random模块用于生成伪随机数。下面的例子中,使用random模块的randint函数,可以生成1~10的任意一个整数数字。随机数的引入可以增强游戏的随机性,让游戏更为有趣。
import random x=random.randint(1,10) print(x)
Python中有一些数据类型,例如列表、字典、集合等,可以用于保存一系列的数据信息。不过对于大规模的数据计算,它们并不都适用。在AI领域的计算中,大规模数据一般以向量形式保存。NumPy模块是专门用于向量计算的模块。让我们看看下面的例子。
首先建立一个列表,再建立一个数组,输出并观察二者的类型,可以看到二者的类型是不一样的。x_list是列表(list)类型的,x_array是NumPy数组类型的。
import numpy as np x_list=[1,2,3,4] type(x_list)
list
x_array=np.array([1,2,3,4]) type(x_array)
numpy.ndarray
NumPy数组类型的重要特点在于支持向量化计算,例如我们要计算数值的平方再求和,如果使用列表类型,需要写一个循环,或者使用列表解析来完成。
x_sum=0 for x in x_list: x_sum=x_sum+x**2 print(x_sum)
30
sum([x**2 for x in x_list])
30
如果使用NumPy数组类型,则更加简单,它可以直接对每个数值做平方运算。通过这个例子可以看到NumPy数组类型的优点,它的向量化计算非常方便、快速。
sum(x_array**2)
30
matplotlib是Python环境中非常重要的绘图模块。因为AI和大规模数据计算有直接关系,所以我们会主要使用matplotlib模块来观察数据中的规律,以及在游戏编程领域中观察各项AI指标的走向。matplotlib模块的功能非常丰富,我们先用一个例子来了解一下。
import numpy as np import matplotlib.pyplot as plt %matplotlib inline
先通过NumPy模块构造两个向量x和y,x表示横坐标的位置,y表示x对应的sin函数值。
x=np.linspace(0,2*3.1415,100) y=np.sin(x)
使用linspace在0~2π生成100个点,然后用向量化计算直接算出100个点对应的sin函数值,再使用plt.plot绘制基础的线图,表现两个向量之间的函数关系。这种图(如图2-5所示)可以将数据的大小反映到坐标位置上,我们可以很容易地观察到sin函数的规律性波动变化。
plt.plot(x,y)
图2-5
Python有一个很重要的特点,就是当我们使用等号进行赋值时,并没有进行复制操作,而仅仅是进行了一次绑定操作。我们来看下面的例子。
x=[1,2,3,4] y=x x[0]=100 print(y)
[100,2,3,4]
可以看到x的第一个元素修改后,y也改变了,因为它们绑定的都是同一个列表对象。代码y=x只是让y变量和已有的列表对象进行了绑定,或者说y只是x的引用。如果一定要进行复制操作,就需要使用copy模块。使用copy模块中的copy函数,y就将x完全复制进行了,不会被x的修改操作所影响。
import copy x=[1,2,3,4] y=copy.copy(x) x[0]=100 print(y)
当x是复合对象时,例如嵌套列表时,情况变得复杂了,此时copy函数进行的是并不完整的复制操作,因为它只能进行所谓的浅复制。
x=[[1,2,3,4],[2,3,4,5]] y=copy.copy(x) x[0][0]=100 print(y)
[[100,2,3,4],[2,3,4,5]]
对于这种情况,我们需要用另一个函数deepcopy,来进行所谓的深复制。
x=[[1,2,3,4],[2,3,4,5]] y=copy.deepcopy(x) x[0][0]=100 print(y)
[[1,2,3,4],[2,3,4,5]]
我们还会使用collections模块中的一些数据结构,例如namedtuple类型,它是带有名称的元组。下面的例子中,我们定义了一个几何意义上的点坐标,如果使用传统的元组,需要使用数字编号来取值,使用名称让代码更容易理解。
from collections import namedtuple Point=namedtuple('Point',['x','y']) p=Point(11,22) print(p[0]+p[1]) print(p.x+p.y)
另一个会用到的是deque类型,它也被称为队列,和列表一样,它可以被遍历,也可以增加元素。它的一个重要特点在于,当指定了最大容量后,新增加的元素补充进右侧尾部,最左侧头部的元素则会被删除。这样实现了先进先出的设计需求。
from collections import deque d=deque('ghi',maxlen=4) d.append('j') print(d) d.append('k') print(d)
deque(['g','h','i','j'],maxlen=4) deque(['h','i','j','k'],maxlen=4)