Python turtle库绘制小黄人完整代码及运行教程

慢慢来
慢慢来
发布时间:2026-10-31 | 5人浏览过
原创

本文提供使用Python内置turtle库绘制经典小黄人的完整源代码与逐步实现教程。涵盖图层分解、坐标几何定位、画笔性能优化及常见运行报错排查,帮助读者在标准Python环境下顺利完成图形绘制。

使用 Python 内置的 turtle 库绘制经典小黄人卡通形象,核心在于将复杂的卡通形体分解为满足“油画师算法”层叠规则的几何图元:底层肢体、胶囊形黄色躯干、牛仔背带工装裤、钛灰双护目镜、眼球高光以及微笑表情。本文提供一套无需安装任何第三方扩展包、在标准 Python 3 环境下可直接拷贝执行的完整源码,并详细拆解图层绘制顺序、坐标几何推导公式、显存加速策略与窗口生命周期管理,帮助读者高效理解代码并成功呈现图形。
Python turtle库绘制小黄人完整代码及运行教程
图 0:小黄人几何骨架拓扑、尺寸标定与图层参数工程蓝图

一、小黄人图层分解与绘制原理

在计算机图形学中,turtle 绘图依赖于“油画师算法”(Painter's Algorithm),即先绘制处于底层(距离观察者较远)的图形对象,后绘制处于表层(距离观察者较近)的图形对象。如果绘图顺序颠倒,例如先绘制了胸前的工装裤口袋,后绘制躯干的大色块,则后绘制的黄色填充将彻底遮挡先绘制的细节。

为了使代码结构清晰、便于调试和维护,我们将小黄人的整体形象自底向上严格划分为 6 个图层:

  1. Layer 1(底层肢体与鞋袜):包含下方两侧的黑色圆角鞋履和两侧伸展的手臂与黑色手套。先绘制手臂与鞋袜,当后续绘制黄色躯干时,躯干的外轮廓会自动遮挡手臂与躯干的连接缝隙,无需处理复杂的交线裁剪。
  2. Layer 2(主体胶囊躯干):小黄人的基础形体是一个上下对称的圆角胶囊体。使用明黄色(#FCE029)填充,左右两条垂直线连接顶底各 180° 的圆弧,形成闭合区域。
  3. Layer 3(工装牛仔背带裤):覆盖在躯干下半部分的经典深丹宁蓝(#2C5282)服饰,包括两侧裤腿、斜向跨越的背带、固定纽扣以及胸口的中央圆角口袋。
  4. Layer 4(护目镜皮带与镜框):贯穿头部左右的黑色皮质固定带,叠加两组对称的钛灰金属外环(#8E99A4)和内嵌镜框槽。
  5. Layer 5(眼球、虹膜与高光点):嵌套在镜框内部的纯白巩膜、棕色虹膜、黑色核心瞳孔以及微小的偏心白色反光点。
  6. Layer 6(面部表情与头顶发丝):最上层的装饰线,包括微翘的微笑弧线唇形和头顶向外辐射的散落发丝。
Python turtle库绘制小黄人完整代码及运行教程
图 1:小黄人 6 阶图层时序栈与空间覆盖架构关系图

二、准备工作与运行环境要求

在运行代码之前,需要明确运行环境的具体要求,避免陷入初学者常见的文件命名与环境配置误区:

  • Python 版本:支持 Python 3.6 及以上任意主流版本。
  • 标准库依赖:turtle 和底层图形引擎 tkinter 是 Python 官方标准库自带模块,绝对不要执行 pip install turtle。第三方 PyPI 上的 turtle 库是多年前为 Python 2 设计的废弃第三方包,安装后反而会在导入时报语法错误。
  • 运行环境形态:建议在具备本地图形界面的操作系统(macOS、Windows 或已安装桌面环境的 Linux)中执行。若在无 X11 图形支持的纯云服务器或远程 SSH 终端中运行,会因找不到显示设备而抛出 _tkinter.TclError 异常。
⚠️ 关键避坑提醒:严禁将脚本命名为 turtle.py
Python 在执行 import turtle 时,会首先在当前脚本所在目录进行模块检索。如果你的文件命名为 turtle.py,Python 会导入脚本自身,导致标准库无法加载,并在运行时报出经典的 AttributeError: partially initialized module 'turtle' has no attribute 'setup' 错误。请务必将文件命名为 minion_drawing.py。
Python turtle库绘制小黄人完整代码及运行教程
图 2:Python Turtle 脚本开发、初始化、图层渲染与生命周期控制流程

三、小黄人绘制完整代码实现

以下为完整的、开箱即用的 Python 代码。代码采用函数模块化封装,每个函数对应一个独立的逻辑组件,并提供详细的参数注释:

# -*- coding: utf-8 -*-
"""
Python turtle 库绘制经典小黄人完整脚本
运行环境:Python 3.x(标准库,无需额外安装依赖)
执行命令:python minion_drawing.py
"""

import turtle as t


def jump_to(x, y):
    """精准跳转画笔至目标坐标,自动抬笔与落笔,杜绝拖拽杂线"""
    t.penup()
    t.goto(x, y)
    t.pendown()


def init_canvas():
    """初始化绘图窗口与基础环境参数"""
    t.setup(width=800, height=800)
    t.title("Python Turtle - 经典小黄人绘制教程")
    t.bgcolor("#F2F6FA")
    t.speed(0)
    # 关闭逐帧动画刷新,显著降低绘图耗时,最后调用 update() 一次性输出全图
    t.tracer(False)
    t.hideturtle()


def draw_feet():
    """绘制底部双脚与黑色圆角鞋履(图层 1:底层)"""
    t.pensize(2)
    t.pencolor("#1E272C")
    t.fillcolor("#1E272C")

    # 左鞋履 (对称中心偏左 -40 左右)
    jump_to(-55, -230)
    t.setheading(0)
    t.begin_fill()
    for _ in range(2):
        t.forward(35)
        t.circle(8, 90)
        t.forward(12)
        t.circle(8, 90)
    t.end_fill()

    # 右鞋履 (对称中心偏右 +20 左右)
    jump_to(20, -230)
    t.setheading(0)
    t.begin_fill()
    for _ in range(2):
        t.forward(35)
        t.circle(8, 90)
        t.forward(12)
        t.circle(8, 90)
    t.end_fill()


def draw_arms_and_hands():
    """绘制双侧手臂与黑色手套(图层 1:底层)"""
    t.pensize(2)
    t.pencolor("#2B2B2B")

    # 左手臂(黄色)
    jump_to(-98, -40)
    t.setheading(220)
    t.fillcolor("#FCE029")
    t.begin_fill()
    t.forward(70)
    t.left(90)
    t.forward(22)
    t.left(90)
    t.forward(65)
    t.end_fill()

    # 左手套(深黑色)
    jump_to(-148, -95)
    t.setheading(210)
    t.fillcolor("#222222")
    t.begin_fill()
    t.circle(15)
    t.end_fill()

    # 右手臂(黄色)
    jump_to(98, -40)
    t.setheading(320)
    t.fillcolor("#FCE029")
    t.begin_fill()
    t.forward(70)
    t.right(90)
    t.forward(22)
    t.right(90)
    t.forward(65)
    t.end_fill()

    # 右手套(深黑色)
    jump_to(148, -95)
    t.setheading(330)
    t.fillcolor("#222222")
    t.begin_fill()
    t.circle(15)
    t.end_fill()


def draw_body():
    """绘制经典黄色胶囊形主体躯干(图层 2)"""
    jump_to(-100, -120)
    t.setheading(90)
    t.pensize(3)
    t.pencolor("#2B2B2B")
    t.fillcolor("#FCE029")

    t.begin_fill()
    # 1. 左侧垂直上延至肩部
    t.forward(220)
    # 2. 顶部半圆拱头 (半径 100,顺时针偏转 180 度)
    t.right(90)
    t.circle(-100, 180)
    # 3. 右侧垂直下延至底部
    t.forward(220)
    # 4. 底部半圆拱底 (半径 100,顺时针偏转 180 度)
    t.right(90)
    t.circle(-100, 180)
    t.end_fill()


def draw_overalls():
    """绘制深丹宁蓝牛仔工装背带裤(图层 3)"""
    t.pensize(2)
    t.pencolor("#1E3448")
    t.fillcolor("#2C5282")

    # 1. 裤身主体与胸口围兜多边形
    jump_to(-100, -120)
    t.setheading(0)
    t.begin_fill()
    t.forward(200)
    t.left(90)
    t.forward(65)   # 裤身右侧高
    t.left(90)
    t.forward(25)
    t.right(90)
    t.forward(30)   # 右胸围兜凸起
    t.left(90)
    t.forward(150)  # 围兜顶部水平上缘
    t.left(90)
    t.forward(30)   # 左胸围兜凹陷
    t.right(90)
    t.forward(25)
    t.left(90)
    t.forward(65)   # 裤身左侧回到底部起点
    t.end_fill()

    # 2. 裤腿下部圆弧贴合胶囊下底
    jump_to(-100, -120)
    t.setheading(270)
    t.begin_fill()
    t.circle(100, 180)
    t.left(90)
    t.forward(200)
    t.end_fill()

    # 3. 裤裆中间暗色分界缝线
    jump_to(0, -120)
    t.setheading(270)
    t.pensize(2)
    t.pencolor("#1A2E40")
    t.forward(50)

    # 4. 左肩斜向背带
    jump_to(-100, -45)
    t.setheading(30)
    t.fillcolor("#2C5282")
    t.begin_fill()
    t.forward(45)
    t.right(80)
    t.forward(18)
    t.right(100)
    t.forward(45)
    t.end_fill()

    # 5. 右肩斜向背带
    jump_to(100, -45)
    t.setheading(150)
    t.begin_fill()
    t.forward(45)
    t.left(80)
    t.forward(18)
    t.left(100)
    t.forward(45)
    t.end_fill()

    # 6. 两端金属固定小纽扣
    for bx, by in [(-72, -35), (72, -35)]:
        jump_to(bx, by)
        t.fillcolor("#1C1C1C")
        t.pencolor("#111111")
        t.begin_fill()
        t.circle(4.5)
        t.end_fill()

    # 7. 胸前弧底工装口袋
    jump_to(-35, -70)
    t.setheading(0)
    t.pensize(2)
    t.pencolor("#1E3448")
    t.fillcolor("#25456E")
    t.begin_fill()
    t.forward(70)
    t.right(90)
    t.forward(30)
    t.circle(-10, 90)
    t.forward(50)
    t.circle(-10, 90)
    t.forward(30)
    t.end_fill()

    # 口袋中心圆形徽标
    jump_to(0, -92)
    t.fillcolor("#1C1C1C")
    t.begin_fill()
    t.circle(9)
    t.end_fill()


def draw_goggles():
    """绘制护目镜皮质固定带与双金属镜框(图层 4)"""
    # 贯穿头部的黑色固定皮带 (Y: 72 到 98)
    jump_to(-100, 72)
    t.setheading(0)
    t.pensize(2)
    t.pencolor("#1A1A1A")
    t.fillcolor("#262626")
    t.begin_fill()
    for _ in range(2):
        t.forward(200)
        t.left(90)
        t.forward(26)
        t.left(90)
    t.end_fill()

    # 左右对称钛灰金属双镜框
    for cx in [-42, 42]:
        # 外圈金属环 (半径 38,落笔点 Y = 85 - 38 = 47)
        jump_to(cx, 47)
        t.setheading(0)
        t.pensize(2)
        t.pencolor("#4B5563")
        t.fillcolor("#8E99A4")
        t.begin_fill()
        t.circle(38)
        t.end_fill()

        # 镜框内嵌暗色槽 (半径 30,落笔点 Y = 85 - 30 = 55)
        jump_to(cx, 55)
        t.setheading(0)
        t.pencolor("#374151")
        t.fillcolor("#5F6B76")
        t.begin_fill()
        t.circle(30)
        t.end_fill()


def draw_eyes():
    """绘制眼白、虹膜、核心瞳孔与微小偏心高光(图层 5)"""
    for cx in [-42, 42]:
        # 1. 纯白巩膜 (半径 27,落笔点 Y = 85 - 27 = 58)
        jump_to(cx, 58)
        t.setheading(0)
        t.pensize(1)
        t.pencolor("#CBD5E1")
        t.fillcolor("#FFFFFF")
        t.begin_fill()
        t.circle(27)
        t.end_fill()

        # 2. 经典深棕色虹膜 (半径 14,落笔点 Y = 85 - 14 = 71)
        jump_to(cx, 71)
        t.pencolor("#633918")
        t.fillcolor("#7B431B")
        t.begin_fill()
        t.circle(14)
        t.end_fill()

        # 3. 黑色核心瞳孔 (半径 7,落笔点 Y = 85 - 7 = 78)
        jump_to(cx, 78)
        t.pencolor("#0F172A")
        t.fillcolor("#0F172A")
        t.begin_fill()
        t.circle(7)
        t.end_fill()

        # 4. 右上偏心反光高光点 (半径 2.5,微小纯白提升灵动感)
        jump_to(cx + 3, 85)
        t.pencolor("#FFFFFF")
        t.fillcolor("#FFFFFF")
        t.begin_fill()
        t.circle(2.5)
        t.end_fill()


def draw_mouth():
    """绘制生动的弧形微笑唇线(图层 6)"""
    jump_to(-35, 20)
    t.setheading(305)
    t.pensize(3)
    t.pencolor("#422A14")
    # 借助平滑圆弧向上拟合出弧形微笑唇
    t.circle(42, 110)


def draw_hair():
    """绘制头顶向外散落发丝(图层 6)"""
    t.pensize(2.5)
    t.pencolor("#1E293B")

    # 5 根发丝的起始绝对坐标、航向角度与步长
    strands = [
        (0, 200, 90, 28),    # 正中央直立发丝
        (-14, 197, 108, 24), # 左侧斜翘发丝 1
        (-28, 192, 125, 22), # 左侧低偏发丝 2
        (14, 197, 72, 24),   # 右侧斜翘发丝 1
        (28, 192, 55, 22),   # 右侧低偏发丝 2
    ]

    for hx, hy, angle, length in strands:
        jump_to(hx, hy)
        t.setheading(angle)
        t.forward(length)


def main():
    """主程序:统筹调度时序拓扑与显存刷新"""
    init_canvas()

    # 严格按油画师算法时序渲染
    draw_feet()
    draw_arms_and_hands()
    draw_body()
    draw_overalls()
    draw_goggles()
    draw_eyes()
    draw_mouth()
    draw_hair()

    # 一次性将缓冲区画面刷入物理窗口
    t.update()

    # 阻塞主线程,保持窗口持续显示,监听鼠标关闭事件
    t.done()


if __name__ == "__main__":
    main()

四、核心绘制函数与坐标几何详解

很多读者在自行修改或模仿 turtle 脚本时,常遇到圆弧画歪、眼球偏出镜框或对称失调等问题。以下结合几何原理详细解析三个关键技术点:

1. 胶囊躯干连续闭合路径计算

小黄人的主体是一根宽 200、高 360 的圆角柱体。我们设腰部水平线为 X 轴,中央轴线为 Y 轴:

  • 躯干起始点设在左腰腹下部 (-100, -120),画笔航向设为 90°(朝正上方)。
  • 向前直行 220 单位到达头顶起拱点 (-100, 100)。
  • 在头顶画半圆拱:由于此时画笔向正上方,若顺时针向右转弯,使用 t.circle(-100, 180)。负半径表示圆心位于画笔行进方向的右侧,圆心坐标即为 (0, 100),画完半圆后画笔精准落在右侧 (100, 100),且朝向自动调整为 270°(正朝下)。
  • 再向下直行 220 单位到达底部起拱点 (100, -120),同样执行 t.circle(-100, 180),平滑闭合回起始点。

2. 同心圆定位与落笔点偏移定理

这是使用 turtle.circle(r) 最容易混淆的概念:circle(r) 的起点是圆周的最下沿,而不是圆心本身!

当画笔朝向为 0°(正右方)时,调用 circle(r) 会逆时针在画笔左侧画圆,圆心位于 (x, y + r)。因此,若我们要以 (cx, cy) 为圆心绘制半径为 r 的同心圆,画笔的初始绝对定位必须落位在 (cx, cy - r)。

Python turtle库绘制小黄人完整代码及运行教程
图 3:小黄人眼眶、巩膜、瞳孔与微笑唇线笛卡尔微观坐标分解图

3. 工装背带多边形与闭合染色

在绘制工装背带裤时,不能仅用画线函数。必须在移动笔尖前调用 t.begin_fill(),在沿边缘绘制完整封闭路径后调用 t.end_fill()。 由于下沿弧度与躯干底部完全重合,我们复用了 t.circle(100, 180) 的底部轨迹,保证了牛仔裤与黄色身体边缘严丝合缝,不产生多余的露白间隙。

五、脚本运行步骤与显示控制

完成脚本编写后,按照以下标准步骤在终端或开发工具中执行:

1. 命令行执行方式

打开系统原生终端(Windows 为 CMD 或 PowerShell,macOS / Linux 为 Terminal),进入保存脚本的目录并运行:

# 进入存放脚本的工程目录
cd /path/to/your/project

# 执行脚本
python minion_drawing.py

2. 渲染速度与显示机制解析

在代码中,我们特意设置了 t.tracer(False) 与 t.update() 的组合。这是编写复杂 turtle 程序的黄金模式:

  • 逐帧渲染模式(默认状态):画笔每向前移动一步、每转动一个角度,Tkinter 都会触发画布重绘。绘制数千个像素点可能需要耗费几十秒,体验非常缓慢。
  • 显存缓冲模式(tracer(False)):彻底关闭界面的中间重绘,所有绘制操作在后台显存中即时完成;在 main() 结尾调用一次 t.update(),瞬间呈现成品画面,耗时低于 0.1 秒。
  • 观察绘制过程:如果你希望直观观察画笔一笔一划的动态绘制轨迹,只需将 init_canvas() 中的 t.tracer(False) 这一行注释掉,并将画笔速度设为 t.speed(6) 即可。

3. 窗口生命周期保持

很多新手反馈“运行后窗口闪了一下就没了”。这是因为 Python 脚本在执行完最后一行语句后,主线程即刻结束,随之销毁了 Tkinter 窗口句柄。t.done() 的作用就是调用底层 Tkinter 的 mainloop() 事件主循环,挂起主线程,保持窗口长久驻留,直到用户主动点击窗口关闭按钮。

六、常见运行报错与图形变形排查

针对执行本教程代码时可能出现的典型报错与图形异常,整理如下速查对照表:

Python turtle库绘制小黄人完整代码及运行教程
图 4:Turtle 关键 API 控制指令矩阵与 4 大高频故障诊断图谱
故障表现 / 报错信息 根本原因分析 具体解决方法
AttributeError: module 'turtle' has no attribute 'setup' 当前目录下或导入路径中存在名为 turtle.py 的脚本,形成了同名模块覆盖。 将该脚本更名为 minion_drawing.py,并删除该目录下自动生成的 __pycache__ 缓存文件夹。
绘图窗口瞬间闪退,控制台直接提示 Process finished 脚本末尾遗漏了阻塞窗口的指令。 在代码最后一行确保存在 t.done() 或 turtle.mainloop()。
图形各个器官之间出现长长的黑色拖拽拉线 在坐标位移时忘记抬笔,或者调用 goto() 前画笔仍处于落笔状态。 严禁直接裸调 t.goto(x, y),必须统一调用封装好的 jump_to(x, y) 函数。
_tkinter.TclError: no display name and no $DISPLAY 在没有 X11 / 桌面 GUI 环境的 Linux 云主机、Docker 容器或纯 SSH 会话中执行。 转移到配备本地桌面系统的环境(Windows、macOS 或安装有桌面环境的 Linux)中运行。
圆弧开口方向相反,嘴巴画成了向下的哭脸 调用 circle() 时的起始朝向(setheading)未设定正确。 每次画弧前检查起始角度。在画唇线前严格执行 t.setheading(305)。

七、关键设计参数与二次创作清单

本套小黄人代码具有良好的参数解耦性。读者可以根据个人审美或创作需求,对核心常量进行二次定制与扩展:

组件对象 对应函数 标准设计参数 扩展修改建议
躯干身形 draw_body() 半宽 R=100,侧身直立高度 H=220 增大 H 可绘制高个小黄人 Kevin(凯文),减小 H 可绘制矮萌小黄人 Bob(鲍勃)。
视觉双眼 draw_goggles() / draw_eyes() 双镜框中心 X ∈ [-42, 42],镜框 R=38 若要绘制经典单眼小黄人 Stuart(斯图尔特),只需将循环改为单一中心 cx = 0,并将镜框 R 放大至 52。
工装色调 draw_overalls() 经典丹宁深蓝 #2C5282 可调整为紫色暗黑版或橙色囚服版,更换填色十六进制代码即可一键换装。

通过掌握图层时序分解、路径连续拟合与坐标绝对定位三大核心技术,不仅能够精准绘制小黄人,还能将相同的方法论迁移到机器猫、皮卡丘等任意二维复合卡通图形的 Python 编程绘制中。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表