共计 5079 个字符,预计需要花费 13 分钟才能阅读完成。
turtle 图形库源于 1966 年诞生的 Logo 语言,是入门 Python 的有趣工具。因其简单便捷的图形化方法、和立即反馈式的绘画效果,成为众多编程入门者的首选。相对于大多数入门教材中枯燥的语法学习,和函数、方法的演练来说,turtle 的趣味性显得别具一格、极富效果。
一直希望能用一篇小短文来讲清楚 turtle,但是尝试组织了几次之后,感觉一篇文章门槛还是有点高,最终决定还是分成两篇,即大家现在看到的“初级篇”和“高级篇”,以利更好的分层次阐述。
一个类库是否利于入门,首先了要解它的背景,它能做什么,不能做什么,没有十全十美的事物,不要期望过高。turtle 原意是水生的龟类,可以译成海龟或乌龟。是由 1966 年 Wally Feurzig 和 Seymour Papert 开发出的一种简单易用的编程语言。我们这里的 turtle 库,指的是 turtle 语言用 Python 的实现,turtle 库现在已进入 Python 的内置模块,位于 Lib/turtle.py,用于绘图。咱们这里选择 turtle 库,主要是用来了解和学习 Python 的贴身入门、语法入门、面向对像入门、认识方向、角度与颜色、简单的数学运算、方法定义、循环与递归等。
在使用 turtle 库之前最重要的事,是需要认识 turtle 的两个坐标、角度系统:standard 和 logo。如下图所示:
这里 standard 模式,也就是标准坐标系,在 turtle 库的使用过程中,默认使用这套坐标、角度系统,即以绘图界面的中心点为坐标圆点(0,0),以 x 坐标正方向为 0 度角,逆时针旋转。不要小看这简单的三句话,这是最基础的约定前提,请熟记于胸,否则编程的时候,容易懵的。
除了 standard 标准坐标系外,在 turtle 库的编程中还经常使用另外一套坐标、角度系统,叫做 logo!对,就是那个 Logo,那个原来的独立编程语言,这套 logo 坐标、角度系统就是用来跟原 logo 兼容的,对于了解过 Logo 语言的用户来说,会更加熟悉,上图:
看出差别来了吗,logo 坐标系是以绘图界面的中心点为坐标圆点(0,0),以 y 坐标正方向为 0 度角,顺时针旋转。跟 standard 坐标不同的地方在于 0 度方向的选择,和旋转方式。在编程中使用 mode() 方法进行切换。
# 切换坐标、角度系统
# mode(‘standard’)
mode(‘logo’)
所以,如果见到这个方法,您首先得切换自己大脑中的坐标、角度系统。:)这是编程的底层逻辑,必需先弄清楚。
接下来,再认识 turtle 的画图方式:落笔、抬笔、清空、设置颜色、粗细等等。
如何让这只乌龟在界面上画一条线呢,就如同咱们用笔写字一样,需要用经过“落笔”、“划过”、“抬笔”、“结束”的过程,用 turtle 库来表达,同样非常直观,翻译成简单的英文就可以:
import turtle as t # 导入 turtle 库
t.pendown() # 落笔
t.forward(300) # 划过 300 个单位的长度
t.penup() # 抬笔
t.done() # 结束
在 IDE 中键入这段代码,执行,就能看到在窗口上画出了这样一条直线。“#”号后面的是注释。(IDE 的选择及环境安装见《第一节》)
用 turtle 画出了 Python 的第一条直线之后,接着来看看怎么“转弯”。下面以绘制一个正方形为例子,演示 turtle 怎么前进、怎么左转、右转。
import turtle as t # 导入 turtle 库
t.pendown() # 落笔
t.forward(100) # 划过 100 个单位的长度
t.left(90) # 左转 90 度
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.penup() # 抬笔
t.done() # 结束
在 IDE 中键入这段代码,执行,就能看到在窗口上画出了一个标准的正方形。
有一点编程基础的小伙伴,立即就可以看出来,上面代码中有四组相同的语句,嗯,这不是可以用循环来实现吗?没错,改进一下:
import turtle as t
t.pendown()
for j in range(4): # 重复执行 4 次
t.forward(100)
t.left(90)
t.penup()
t.done()
放到 IDE 中执行,可以看到效果跟顺序执行的完全一致。range()是 Python 的内置函数,这里表示循环执行的次数。
注意缩进,Python 中不使用括号来表示语句块,而靠冒号: 和后面的缩进 (空格缩进) 来表示语句块。因此缩进成为了语法的一部分,要严格遵循,从其它语言转过来的小伙伴需要习惯一下。
学习任何一项新知识,就像爬坡一样,有个量变积累到质变的过程。接下来就来写一个乌龟爬坡的小程序吧,上代码:
import turtle as t
t.pendown()
t.forward(50)
t.left(90) # 左转 90 度
t.forward(50)
t.right(90) # 右转 90 度
t.forward(50)
t.left(90)
t.forward(50)
t.right(90) # 右转 90 度
t.forward(50)
t.left(90)
t.forward(50)
t.right(90) # 右转 90 度
t.penup()
t.done()
放到 IDE 中执行,可以看到一段 3 次爬坡的动画。left(90)是向左转动 90 度;right(90)是向右转动 90 度。当然这 3 次爬坡,也是可以用顺序来做的,代码如下:
import turtle as t
t.pendown()
for j in range(3): # 重复执行 3 次
t.forward(50)
t.left(90) # 左转 90 度
t.forward(50)
t.right(90) # 右转 90 度
t.penup()
t.done()
for 循环的执行效果,跟顺序执行的完全一样,更改 range(3)的参数,可以执行不同的次数。
彩蛋来了:turtle 既然是乌龟,我怎么画到现在没有看到一只乌龟呢?的确有点奇怪,明明是一个小箭头一直在画画,为什么要说成是 turtle 乌龟呢?
不要着急,加一行小代码,乌龟立即出现:
t.shape(‘turtle’)
把这行代码,加到“落笔”的前面,就会发现小箭头变成小乌龟了,还是挺萌吧!上面画直线、画正方形、爬坡三个例子你都可以加上试试试试!
上面的 left(90)和 right(90)分别表示左转 90 度和右转 90 度,那怎么设置乌龟的角度,让它向我们指定的任意方向前进呢?嗯,调整 90 这个参数,在界面上画一个自己的名字吧!哦,中文就算了,画出来太复杂,画个拼音首字母还是可以的,上代码:
import turtle as t
t.mode(‘logo’) # 切换成 Logo 坐标、角度系统
t.shape(‘turtle’) # 显示出小乌龟
t.penup() # 抬笔,先不要画
t.goto(-200, 100) # 移动到起始点
t.setheading(180) # 设置要画的方面,Logo 坐标的 180 度方向,即向下
t.pendown() # 落笔,准备开始画第一个字母
t.forward(200)
t.left(90)
t.forward(100)
t.penup() # 第一个字母 ”L” 画完,抬笔
t.forward(100) # 到达第二个字母的起始位置
t.pendown() # 落笔,准备开始画第二个字母
t.left(90)
t.forward(200)
t.right(135)
t.forward(100)
t.left(90)
t.forward(100)
t.right(135)
t.forward(200)
t.penup() # 第二个字母 ”M” 画完,抬笔
t.done()
在 IDE 中运行这段代码,可以看到小乌龟在窗口左侧画了两个大写的字母“L”和“M”。需要注意的地方是,程序中使用 mode(‘logo’)切换到了 Logo 的坐标、角度系统,setheading(180)将小乌龟的前进方向设置为 Logo 坐标的 180 度方向,即向下的方向,如果有疑问,可以参考本文开篇时对坐标系的描述。
goto(x, y)是一个新方法,可以让小乌龟去到界面上的任意一个坐标点。(当然,画名字的这个小例子,如果全部使用 goto(x,y)会比使用 forward()要简单很多,具体代码你可以自己尝试)
配合 for 循环、forward()和角度度化,可以让 turtle 在变与不变中创造出很多有意思的图形。比如把上面画正方形的例子稍做变化:
import turtle as t
t.pendown()
for j in range(10): # 重复执行 10 次
# 画正方形 - 开始
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90) # 画正方形 - 结束
# 右转 36 度
t.right(36)
t.penup()
t.done()
执行后,可以看到,画出一个非常规整、漂亮的组合图案。
填充,可以让 turtle 的图形更炫丽。主要有以下几个方法:
t.pencolor(‘red’) #设置画笔的颜色
t.fillcolor(‘green’) #设置填充的颜色
t.begin_fill() #开始填充
t.end_fill() #结束填充
下面来改造一下我们前面画正方形的例子,
import turtle as t
t.pencolor(‘red’) #设置画笔的颜色
t.fillcolor(‘green’) #设置填充的颜色
t.pendown()
t.begin_fill() #开始填充
for j in range(4):
t.forward(100)
t.left(90)
t.end_fill() #结束填充
t.penup()
t.done()
执行一下,可以看到 turtle 画出一个红色边框的实心绿正方形。
在 Python 中使用 def 进行方法定义或者叫函数定义,可以让指挥 turtle 画画这件事,更轻松一点。再次改造一下上面画正方形的例子:
import turtle as t
def drawRect(): # 定义一个函数,名为 drawRect()
t.pendown()
for j in range(4):
t.forward(100)
t.left(90)
t.penup()
drawRect() # 调用这个函数
t.done()
在这个例子中,我们使用 def 定义了一个函数,名为 drawRect(),内容就是带一个正方形,跟前面的描述一样。
自定义好函数以后,只要调用这个函数名,就可以执行函数体内的代码内容。我们再来丰富一下这个例子,对上面画多个正方形的例子进行优化:
import turtle as t
def drawRect(): # 定义函数
t.pendown()
for j in range(4):
t.forward(100)
t.left(90)
t.penup()
for j in range(10): # 重复执行 10 次
drawRect() # 调用这个自定义的函数
t.right(36)
t.done()
执行一下,可见效果一样,但是代码更为简洁,可读性更好。
下面给这段代码加上填充效果:
import turtle as t
def drawRect():
t.pendown()
for j in range(4):
t.forward(100)
t.left(90)
t.penup()
clrs = [‘red’, ‘green’, ‘blue’, ‘gray’, ‘brown’] # 颜色列表
for j in range(10):
t.fillcolor(clrs[j % 5]) # 从列表中选择颜色
t.begin_fill() # 开始填充
drawRect()
t.end_fill() # 结束填充
t.right(36)
t.done()
运行一下这个小例子,可以看到,turtle 画出了用五种不同颜色填充的正方形组合图案。例子中为了使得每个正方形填充的颜色不一样,我们先定义了一个颜色列表 clrs,列表 clrs 中预先存入了 5 个颜色。在 for 循环中,每次执行时根据 j 值的变化,用取余数 % 的方式,每次取到不重复的颜色。
当然,turtle 的功能不只于此,对于 Python 的入门者来说,通过 turtle 生动的例子,可以画漂亮的图形,也可以同时熟悉 Python 的语法和规则,何乐而不为呢?
期待我们下一节《高级篇》,用 turtle 画更有趣的图形、更深入的应用 Python 吧!