本节书摘来自华章计算机《树莓派Python编程指南》一书中的第2章,第2.1节,作者:(美) Alex Bradbury Ben Everard更多章节内容可以访问云栖社区“华章计算机”公众号查看。
第2章 Python简介
本章通过一些代码示例来逐步介绍Python。你不必了解这些代码的所有细节,本章只是带你领略下编程的感觉。你将会学到如何在屏幕上绘画,甚至如何编写简单的游戏。同时,你将会学到一些编程的基本概念。如果无法完全理解本章中的程序,不用担心,我们会在后面章节中做详细介绍。
2.1 使用Turtles绘画
是时候开始编程了!我们强烈建议你将代码一行行输入IDLE3,这样可以帮助你理解每行都做了什么事情。言归正传,打开IDLE3,点击File→New Window,然后输入:
然后点击Run→Run Module或者按F5键来运行程序。此时会跳出一个对话框让你输入文件名。起什么名字都可以,但起一个容易理解的名字可以帮助我们记住它(这里我们使用chapter2-example1.py)。
文件中每一行都是一个Python指令。Python一行行检查它们,然后按照先后顺序来执行。图2-1显示了计算机执行完所有步骤后的结果:在屏幕上画出一条直线,直线上面连接一个圈。看起来像棒棒糖,实际上,这是一朵花的第一部分。如果你的屏幕没有显示出这个结果,请检查下文件的每一行是否正确,然后再试一次。
接下来我们仔细看下Python是如何根据代码来工作的。
在Python程序的开头部分,通常会有一些import行。它们为程序导入一些附加特性,就像其他软件中的附件或者插件一样。这些特性被分成不同的模块。后面章节中将介绍更多的import命令。本例中我们仅导入turtle模块以完成绘图工作。
接下来的代码:
创建了一个新窗口用于绘图,并定义了一个动作,单击窗口就可以将其关闭。
下面这行代码使用了我们在第一行中导入的turtle模块创建的一个名字叫babbage的turtle对象(Charles Babbage,计算机先驱,创造了计算机的概念)。
https://yqfile.alicdn.com/f72c19061d0abfa2b55a00e0ecf59ed6cac8ec38.png
" >
Babbage有很多个方法可供我们使用。例如下面这行:
https://yqfile.alicdn.com/412d48be40e2bd23c083858387e2845921c9be04.png
" >
使用了left()方法,使babbage向左转一定角度。位于left()方法后面括号里的参数可以控制该方法运行时的角度。本例中,输入参数为90,因此babbage向左转90°。下一行使用了forward()、right()和circle()方法。
https://yqfile.alicdn.com/d32198f5a9b449132d9eac1b38d97085d71248d0.png
" >
第一个方法将turtle向前移动100个像素,第二个将其右转90°,最后一个画了一个半径为10像素的圆。
现在开始添加花瓣。按下面例子编辑代码(变化部分已经用黑体标出):
运行后会看见这朵花已经有了第一片花瓣。注意我们添加了一些带#符号的行,计算机将忽略以#开始的行。因此我们可以用这种方法添加注释(或者其他任何阅读代码的人)。它增加了程序的可读性。当我们几天、几周甚至几年后再来看这段代码,有了注释就可以很容易地理解它做了什么。
2.1.1 使用循环
画花瓣的部分很容易理解(我们使用三角函数来计算出两个左转之间的夹角,但不用担心,我们不会陷入数学计算中)。
现在可以添加一段新代码来画第二片花瓣(总共要画24片花瓣)。和画第一片花瓣完全相同,因此只要复制粘贴就可以得到下列代码:
然后,重复22次画出剩余花瓣。好吧,够了,根据编程的一般经验法则,不能重复出现相同的代码。假设你要改变花瓣尺寸,而且需要改48个地方(每片花瓣两次),如果忘记任何一个地方,将会得到一个不靠谱的图片。因此,你可以使用循环,用一小段代码告诉计算机反复执行特定部分的代码。
你可以用下面代码来替代从#画第一片花瓣(#draw first petal)开始的所有代码:
https://yqfile.alicdn.com/ae323d84dd40c3a7cc033ef9f8c8b2a361fcf158.png
" >
我们将会在第3章中介绍注释后面的第一行代码。现在,只需要理解它表示重复运行后面那段代码24次之后,计算机将执行这块代码后的下一个命令。
Python中循环(或者之后接触的其他类型条件)的代码段通常使用相同的格式。第一行以冒号结尾,之后的每一行都使用相同的缩进。当tab或者缩进结束时,Python就认为该代码段结束了。如果你之前使用过其他编程语言,将会发现Python的做法和其他语言有所不同。
运行代码后,你会发现babbage转了一圈将所有花瓣都画完了。我们得到了图2-2所示的完整花朵。
仅用13行代码,干得不错。当然,不是所有的花都是黑色的,在图片中添加点颜色会更好看点。turtle模块提供了一些方法让我们可以选择画线的颜色。下面对前面的代码做了些修改(更改部分以黑体显示)。
上述代码中,我们使用了color(colour1, colour2)方法(英国人应该看得出来该方法的名字是美式写法)。这里colour1是画笔色,colour2是填充色。画完花朵中心后,我们告诉计算机用begin_fill()方法填充中心。然后,我们调用end_fill()方法,以防它填充所有的花瓣。
2.1.2 条件处理:if、elif和else
现在继续向IDLE3输入画花朵程序的后半部分:
https://yqfile.alicdn.com/3c02168418f0cf5d8a4a85166c0d3cdd37a96a2d.png
" >
我们使用点艺术眼光,决定用红、橙、黄三种颜色来绘制这朵花的叶子。由于这是本黑白印刷的书,只有在树莓派上运行程序之后,才能看到彩色图像。当然也可以通过本书网站上的flower.png来查看结果。为了转换花瓣色彩,我们使用了if ... elif ... else语句。它告诉Python根据不同的数据做不同的事情。基本结构如下所示:
这里的表示条件,可以为真或假。本例中,我们使用如下条件:
babbage.color()(注意该方法不带任何参数)告诉应用程序我们当前使用的颜色。不同于我们之前遇到的方法,它反过来给我们输出了一些信息。它的返回值是一对颜色——第一个是画笔色,第二个是填充色(从画完花朵中心之后,我们就没有改变过这两个颜色,因此程序的后继部分仍然使用它们)。双等于号(==)表示“相等”。使用双等于号是因为等号已经被定义为“赋值”,我们在创建window和turtle对象时已经使用过等号。
如果条件为真(本例中,如果turtle的颜色为(“red”, “black”)),Python将执行if之后的代码。如果条件为假,Python将转而执行elif(elif是else if的简写)。这里的判断条件和if一样。
如果elif处的条件为假,Python将转到else处执行。到此为止(也就是说,if和elif处的判断条件都为假),Python将执行else之后的代码。else处没有判断条件。图2-3描述了上述逻辑流程。
https://yqfile.alicdn.com/c49a9a560b56ad524333fe03c4d856b36448e6dc.png" >
这些if语句能够在画完一个花瓣后改变画笔颜色。我们在程序后面新加了下面这行:
它会隐藏turtle(鼠标),以保证鼠标不会遮挡我们的图片。至此,我们的第一个Python程序圆满完成。
2.1.3 使用函数和方法组织代码
在开始第二个Python程序之前,我们先停下来讨论下“方法”。从前面的代码可以看出来,方法能够有效地控制程序。在前面的例子中,我们使用它们来移动turtle,改变颜色或者创建窗体。每次都调用这些方法来完成某些事情。例如,通过babbage.forward(50)来调用babbage的forward(50)方法,通过window.exitonclick()来调用window的exitonclick()方法。每次调用这些方法,都会运行保存在Python模块中的相应代码。Python还有个相似的特性——函数。函数和方法的工作方式有点类似,但是函数不需要import任何模块。例如,在Python解释器中输入:
这行代码将运行print函数,将参数输出到屏幕上。是否还记得我们前面提到的不要在程序中出现重复的代码?当时我们说可以使用循环和函数来减少重复。例如,现在需要一个根据给定半径计算圆周长的程序。如果听过数学课都知道圆周长等于2×pi×r(如果没有上过数学课也没关系,只需要跟着做就好了)。每次在计算时重写代码可能会使问题变得复杂(如果某个地方写错了圆周率(pi)的值,将会导致一系列很难发现的问题)。因此我们创建一个函数来完成它。在Python中是这样做的:
这里我们使用了两个函数嵌套在一起。circlearea(1)计算半径为1的圆周长,print()把计算结果输出到屏幕上。
我们使用关键字def定义了一个自己的函数。def之后是函数名,接下来的小括号里是参数。在程序中可以直接使用这些参数,参数值在函数调用时传递过去。关键字return告诉Python我们的返回值是什么。因此,在前面的例子中,当Python发现circlearea(1)时,将会把1作为参数radius的值传入函数,然后执行def circlearea(radius)。接着,它返回计算结果(6.28)给函数print。以后你将会看到,方法也可以像函数一样,一个方法通过嵌套将信息传递给另外一个方法。这是一种非常有用的方法,可以在程序的不同部分间传递数据流。