这一部分主要面向数模活动中的python基础知识进行讨论
作者
系列文章(科学计算Python2小时)目录:李似:科学计算Python2小时-前言与目录zhuanlan.zhihu.com
首先要说明的是,目前常用的Python版本包括Python2和Python3,二者有一些语法和一些包是互不兼容的。部分Python的拓展库已经放弃了对Python2的支持所以本分文档推荐使用Python3作为解释器。当然对于数学建模而言,Python2也是一个可选的方案,但是可能会在使用过程中遇到一些问题,如果你是Python2的忠实拥护者,那么使用Python2来完成数学建模工作,也未尝不可。
接下来我们可能需要理清几个概念解释器,文本编辑器,IDE和包管理工具
解释器
一般我们编写Python源程序时,会得到一个后缀名为py的文件,当你想要运行这份代码的时候,操作系统是不能够认识py这份文件怎怎么样工作的,这时就需要一个解释器,将这份文件翻译成机器可以识别的机器码。
通常我们在网络上看到一些教程说,我们可以直接去Python的官方网站上下载某一个版本的Python,并将它们安装在我们自己的电脑上,那么这里我们所安装的Python其实就是解释器。
如果说的更明确一些,他应该被称为CPython解释器,一个用C语言写的Python解释器,当我们在命令行中运行下面这行代码的时候,其实就是它在执行作用
python demo.py
IPython是另外一种Python解释器,与其说它跟CPython上有什么不同,还不如说它只是在CPython的交互方式上进行了一些改进,IPython使用代码块的方式展现和运行代码。
CPython使用>>>做命令提示符,而IPython使用IN[num]作为命令提示符,从这里可以就可以很容易的把二者分辨开.
比如在命令行中进行Python或者在pycharm这类软件中运行Python使用的都是CPython解释器
而在jupyter notebook或者spyder这样的软件中运行,用的都是IPython解释器
二者并没有什么明显的区别,当我们已经完成了功能的测试时,我们可以使用CPython来进行大规模的计算,到我们测试功能时,我们可以使用IPython来进行交互式的代码书写。如果要进行一些展示性的或者教程性的代码书写的时候,使用IPython一般是比较友好的一种展示方式。
文本编辑器
就像电脑中最常用的记事本软件一样,文本编辑器其实就就是用来敲代码的一个界面而已但是有一些文本编辑器,集成了代码补全、代码高亮、缩管理之类的插件,所以在代码的编写中会用的比较顺手。
比如记事本,Vim,VSCode都是常用的文本编辑器
通常使用纯文本编辑器编辑好的程序,需要在命令行中调用对应的文件来运行它
IDE
集成开发环境(IDE,Integrated Development Environment )是用于提供程序开发环境的应用程序,使用集成开发环境的好处在于你可以在一处完成代码测试编写到运行的所有步骤,通常在侧边栏它会有文件夹的管理,在占程序空间的大块的区域,会有代码编写的位置,一些菜单栏会提供给你运行程序和显示程序运行结果的按键和区域。
甚至相当一部分IDE还会贴心的给你安装好Python的运行环境。(我说的就是Anaconda)
诸如 Anaconda,pycharm,spyder,VS 都属于集成开发环境
包管理工具
原生的Python其实并没有什么特别强大的功能,许多常用的科学计算软件包或者绘图软件包比如我们熟知的numpy或者matplotlib,都是独立出来的程序库,那怎么样把他们导入到我们的程序中,并且为我们所用呢?这时候就需要包管理工具,常用的包管理工具有pip和conda
一般情况下再安装好Python的解释器之后,pip就是默认的包管理工具,你可以在命令行中使用pip install来安装某些你想要的包。这时候 Pip会从网络上把对应的软件包下载下来,并且安装到你的电脑上,但是Python默认的下载源在国外,所以下载速度会比较慢,这里推荐使用清华大学的镜像源,来下载你所需要的软件包。
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple [软件包名字]
许多情况下,当你iimport某个包时它会报错,那么问题就在于这个包你根本没有安装和下载过,那么使用上面这一条代码在命令行中运行,基本就可以解决问题。
Hello world
等你完成安装Python环境以及相关软件的一些工作之后,就可以开始正式的踏入Python的世界了,那么其实任何编程语言的第1步都是一样的,打印出hello world。尝试运行以下这行代码
print("Hello wold")
Hello wold
那么接下来将这个部分,我们将开始进行Python科学计算的一些基本常识的了解
在Python中行注释的用法是在当前行最前面加一个井号 #,而多行数式是用三个单引号或者三个双引号将代码块框起来
而在大部分的文本编辑器或者IDE中如果你想在很多行前面都加一个井号来做单行注释,那么对应的快捷键是Ctrl+/,(这个超级好用)
# 这是一行注释
# 这也是一行注释
# 这还是一行注释
这是一行忘加的注释符号的注释
那么就可以清晰的看出来,我们引入了一个错误,他表示这一个变量没有被定义.
在代码的编写过程中,你可能会遇到很多这样类似的问题,善用搜索引擎之前需要先读一下他到底是说了些什么,就我们这点英语水平,还是能读懂他的报错的很多报错都已经将问题出现原因讲得很清晰了。
运算与数据类型
在Python中一个变量,如果你想要使用它,其实你并不用像C一样首先去定义,直接用它来计算就好了。
数据类型
a = 2
b = 3
c = 4
str_ = "a,b,c"
strWithFormat = "{},{},{}".format(a,b,c)
list_ = [a,b,c]
tuple_ = (a,b,c)
map_ = {"a":a,"b":b,"c":c}
print("字符串:\t",str_)
print("带占位符的字符串:\t",strWithFormat)
print("列表:\t",list_)
print("元组:\t",tuple_)
print("字典:\t",map_)
#更多关于数据类型:Python 变量类型 | 菜鸟教程
字符串: a,b,c
带占位符的字符串: 2,3,4
列表: [2, 3, 4]
元组: (2, 3, 4)
字典: {'a': 2, 'b': 3, 'c': 4}
运算
# 加减乘除
print(a+b)
print(a-b)
print(a*b)
print(a/b)
# 对结果四舍五入
print(round(a/b))
# 取余
print(a%b)
#更多关于运算:Python3 运算符 | 菜鸟教程
5
-1
6
0.6666666666666666
1
2
部分数学函数
判断与循环
balls = ['white','white','white','otherColor','white','white','otherColor','otherColor','otherColor','white','white','otherColor']
numOfWhiteColorBalls = 0
numOfOtherColorBalls = 0
for ball in balls:
if ball == 'white':
numOfWhiteColorBalls += 1
else :
numOfOtherColorBalls += 1
if numOfWhiteColorBalls == 0:
print("There has no white ball in all {} balls".format(numOfWhiteColorBalls+numOfOtherColorBalls))
elif numOfWhiteColorBalls == 1:
print("There is 1 white ball in all {} balls".format(numOfWhiteColorBalls+numOfOtherColorBalls))
else :
print("There are {} white balls in all {} balls".format(numOfWhiteColorBalls,numOfWhiteColorBalls+numOfOtherColorBalls))
#更多关于判断和循环语句:
# Python 条件语句 | 菜鸟教程
# Python 循环语句 | 菜鸟教程
There are 7 white balls in all 12 balls
这段代码运用到了相当多的知识点和需要讨论的部分。
首先你所有的变量都应该有意义,可以使用下划线命名法或者驼峰命名法来对你的变量进行命名。
其次for循环可以对相当多的数据类型进行迭代,其中列表就是一个有迭代能力的数据类型,代码中ball在循环中指的是每一个球的颜色
在Python中没有像C语言中i++这样的变量自增方法,你可以使用+= 1代替它
Python中没有像C语言中那样使用分号来作为每一行代码的结尾,但是Python对于缩进的要求相当严格,像很多初学者常犯的问题都是出现在缩进上面
下面这一幅动图是在循环和判断中的一个流程
函数
函数指的是一段可以执行特定功能的代码段,一般又称为子程序。函数存在的意义是可以将大量的重复性工作打包成一个固定的流程,当你给这个流程一些符合条件的输入时,在这个程序里面进行计算之后返回给你计算的结果。
函数之间可以相互调用,这个特性也促成了一些算法的实现,比如递归。
那在数学建模这种使用程序代码来帮助我们运算的应用背景下,一般都是我们有一系列的数据,需要经过相同或者类似的处理,那这个时候我们就把他们一个一个送进写好的函数中,再去接收他返回回来的输出,这样就可以起到批次计算的效果。
接下来我们把上一个例子用函数来重新写一遍。
def countSelectColorBalls(balls,selectColor):
numOfSelectColorBalls = 0
numOfOtherColorBalls = 0
for ball in balls:
if ball == selectColor:
numOfSelectColorBalls += 1
else :
numOfOtherColorBalls += 1
if numOfSelectColorBalls == 0:
print("There has no {} ball in all {} balls".format(selectColor,numOfSelectColorBalls+numOfOtherColorBalls))
elif numOfSelectColorBalls == 1:
print("There is 1 {} ball in all {} balls".format(selectColor,numOfSelectColorBalls+numOfOtherColorBalls))
else :
print("There are {} {} balls in all {} balls".format(numOfSelectColorBalls,selectColor,numOfSelectColorBalls+numOfOtherColorBalls))
return {selectColor:numOfSelectColorBalls}
balls = ['white','white','white','yellow','white','white','yellow','red','yellow','white','red','red','blue']
ballColorList = []
ballColorList.append(countSelectColorBalls(balls,"white"))
ballColorList.append(countSelectColorBalls(balls,"black"))
ballColorList.append(countSelectColorBalls(balls,"yellow"))
ballColorList.append(countSelectColorBalls(balls,"red"))
ballColorList.append(countSelectColorBalls(balls,"blue"))
print(ballColorList)
#更多关于函数:
# https://www.runoob.com/python3/python3-function.html
There are 6 white balls in all 13 balls There has no black ball in all 13 balls There are 3 yellow balls in all 13 balls There are 3 red balls in all 13 balls There is 1 blue ball in all 13 balls [{'white': 6}, {'black': 0}, {'yellow': 3}, {'red': 3}, {'blue': 1}]
在这个例子中,我们把主要的运算部分包装成了一个叫做countSelectColorBalls的函数,这个函数有两个输入参数,返回值是颜色和对应该颜色的球的个数,其外还打印了一些输出在屏幕上.两个输入参数分别是balls和selectColor,代表了球的列表和被选择的颜色。返回值是一个以所选颜色为key,以所选颜色球的个数为value的字典,在主程序之外使用一个列表接收返回值,append指的是将参数接到列表末端。
之后我们将上一个例子中对白球的计数器换成了对所选颜色的球的计数器,使它对其他的颜色也同样具有适配性。
这里我们看到仍然有几行代码是高度重复的,那么我们可以用下面的例子来替代它。
ballColorList = []
for color in set(balls):
ballColorList.append(countSelectColorBalls(balls,color))
print(ballColorList)
There are 3 yellow balls in all 13 balls There are 6 white balls in all 13 balls There are 3 red balls in all 13 balls There is 1 blue ball in all 13 balls [{'yellow': 3}, {'white': 6}, {'red': 3}, {'blue': 1}]
set是一种叫做集合的数据类型,它的特点就是集合内的元素是不重复的.那么对一个列表取集合,就能够得到里面不重复的所有元素。在将每一个颜色作为函数的输入值进行查询和运算。就能够得到相同的效果。
日期和时间 这里有一个计算机中非常常见的关于时间的概念叫做时间戳,它指的是从1970年1月1日零时开始的时间秒数或者毫秒数.
import time # 引入time模块
ticks = time.time()
print("当前时间戳为:", ticks)
#更多关于日期和时间:
# https://www.runoob.com/python3/python3-date-time.html
当前时间戳为: 1611793367.7136235
时间戳基本上就是所有关于时间的运算的基础,包括计算时间差值转换成日期,或者转换成其他什么别的格式。
当然在Python中还包括了一些其他关于时间的操作,不用我们自己从时间戳开始转换。
这里我们只做一些比较基本的示例,更多的更具体的使用方法,可以去参考其他的教程。
为了方便后面的运算,我们先上两个函数。
# 输出指定范围内的所有质数算法1
def primeList_1(numMax):
primes = []
for num in range(2,numMax):
for m in range(2,num):
if num % m == 0:
break
else:
primes.append(num)
return primes
# 输出指定范围内的所有质数算法2
def primeList_2(numMax):
primes = []
numsList = []
for i in range(numMax):
numsList.append(True)
for num in range(2,numMax):
addSum = num + num
while addSum < numMax :
numsList[addSum] = False
addSum += num
for i in range(2,numMax):
if numsList[i]:
primes.append(i)
return primes
# 计算程序运行时间
import time
ticks1 = time.time()
primeList_1(50000)
ticks2 = time.time()
print("时间差为:", ticks2-ticks1)
ticks1 = time.time()
primeList_2(50000)
ticks2 = time.time()
print("时间差为:", ticks2-ticks1)
时间差为: 6.9387428760528564 时间差为: 0.04651689529418945
其实这个时间差计算还挺简单的,主要就是在代码块前面打一个时间戳,在代码块后面打一个时间戳把两个时间戳做一下减法就可以了。
那么这里额外还要再说几个比较有价值的点。
首先看函数primeList_1定义的第6行和第9行,这是一个for else结构 else在前面的for中break生效时会生效。
再有就是当我们写程序时需要考虑城市的时间复杂度的问题,我们能看到上面的一端程序,第1种算法执行6-7秒,而第2种方法只需要执行0.04-0.06秒,效率差了100多倍,这就是一个很普通的计算质数的两种方法,在其他的问题中也有类似的优化途径,如果当你的循环达到了两层或者三级以后,你就可能需要用一些方法来进行优化。