Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

PyFirst

09. 字符艺术家

谁说编程只能处理数据和文字?用循环 + 字符串,你的代码也能变成画笔,在屏幕上画出漂亮的图案 🎨

🎨 Python 魔法学院 · 艺术工坊(特别篇)

在魔法学院的东塔,有一间洒满星光的画室。这里的画家不用颜料和画布——他们用字符作画。一个 * 就是一颗星,一个 # 就是一块砖,层层叠叠的循环就是画笔的轨迹。

今天你将学会「字符画术」:用循环画出三角形、菱形、圣诞树,甚至一颗会跳动的爱心。代码不是冷冰冰的指令——它是你手中的画笔。


🤔 为什么要学字符画?

你在纸上画过画吗?一笔一笔,从左上角画到右下角。程序的"画笔"也是一样——它从上到下一行一行地输出,和我们写字完全一样!

字符画的秘密就是:把屏幕想象成一张方格纸。每一行该有几个空格、几个星星,你提前"算"出来,然后让循环去执行。

💡 生活联想:你有没有玩过乐高?每一块积木的位置都是算好的。字符画就是"用代码搭乐高"——先用脑把图案拆成一行一行的,再用 for 循环把每一行拼出来。


9.1 三角形——从简单开始

画之前想一想 🤔

如果让你在纸上画一个等腰三角形,你会怎么画?

  1. 先确定最底下一行是几个星星

  2. 从第一行开始,每行星星数量依次递增:1, 3, 5, 7...

  3. 为了让三角形居中,你需要先画一些空格——第 i 行前面有多少个空格?

规律来了:假设三角形高 6 行(第 0 行到第 5 行),第 i 行前面需要 6 - i - 1 个空格,星星数则是 2 × i + 1

🧠 思维训练:编程前先在草稿纸上画一个 3 行的迷你三角形,标出每一行的空格数和星星数。把这个过程"翻译"成代码,就是循环逻辑。

Python
14
准备加载编辑器...
🔧 正在准备编程环境...0%
等待编辑器...
等待 Python 环境...

💡 规律:第 i 行有 2*i+1 个星星。试试改 height 的值,画出不同大小的三角形!

⚠️ 常见误区 #1range(1, 8) 中的 i 是从 1 开始的!如果你用 range(8)(从 0 开始),就需要调整公式。把起始索引和公式对齐,是字符画最容易出错的地方。

⚠️ 常见误区 #2:很多人搞混"行"和"列"——外层 for i in range(height) 控制的是(从上到下),内层 "⭐" * (2 * i + 1) 控制的是该行有多少个星星(从左到右)。记住:外层 = 换行,内层 = 内容

🧪 试试看:把等腰三角形的 height 分别改成 3、8、12,观察三角形的大小变化。再试试把 "⭐" 换成 "❤️",看爱心三角形长什么样!


9.2 菱形——对称之美 💎

画之前想一想 🤔

菱形看起来很复杂?其实它就是一个正三角形 + 倒三角形叠在一起!

想象你把一张纸对折:上半部分从尖角画到最宽处,下半部分从最宽处画回尖角——两个三角形的代码几乎一模一样,只是下半部分的循环方向反了

🧠 思维训练:在纸上画一个 5 行的菱形,标出上半部分和下半部分的分界线。你发现了吗?最宽的那一行(中间行)只出现一次,所以下半部分从 size - 2 开始往回数。

Python
14
准备加载编辑器...
🔧 正在准备编程环境...0%
等待编辑器...
等待 Python 环境...
Python
14
准备加载编辑器...
🔧 正在准备编程环境...0%
等待编辑器...
等待 Python 环境...

⚠️ 常见误区range(size - 2, -1, -1) 为什么是 -1 不是 0?因为 range 的结束值不包含。写成 range(size - 2, -1, -1) 才能包括到第 0 行。试试改成 range(size - 2, 0, -1) 看看会少掉哪一行!

🧪 试试看:把菱形的 size 参数从 5 改成 8,画一个超大的钻石!再试试把 "◆" 换成 "💠""✨",看效果有什么不同。

🏆 挑战升级:你能画出"蝴蝶结"图案吗?提示:左边一个三角形、右边一个对称三角形,中间用空格隔开。这需要你在每一行输出 左边 + 空格 + 右边


9.3 圣诞树——节日气氛 🎄

画之前想一想 🤔

圣诞树分成三个部分:树冠(三角形状的绿叶)、树干(下方的棕色方块)、礼物(最底下的装饰)。

树冠其实就是一个等腰三角形!不同之处在于:树冠多了一层偏移(前面多几个空格让树看起来居中),而且用的是 "🟢" 而不是星星。

🧠 分解思维:复杂图案 = 多个简单图形拼在一起。圣诞树 = 三角形 + 矩形(树干)+ 一行文字(礼物)。编程的秘密就是"分而治之"——把大问题拆成小问题,一个一个解决。

Python
14
准备加载编辑器...
🔧 正在准备编程环境...0%
等待编辑器...
等待 Python 环境...

🧪 试试看:把 height 从 6 改成 10,画出参天大树!把树叶从 "🟢" 改成 "🎄" 或者 "🍀",试试不同的节日风格。

🏆 挑战升级:你能在树冠上随机点缀一些 "🎀""⭐" 装饰球吗?提示:用 random.choice(["🟢", "🎀", "🟢"]) 代替固定的 "🟢"


9.4 沙漏——时间的形状 ⏳

画之前想一想 🤔

沙漏和菱形有什么不同?菱形是上面小 → 中间大 → 下面小,而沙漏是上面大 → 中间小 → 下面大

所以沙漏 = 把菱形倒过来——上半部分从宽往窄画,下半部分从窄往宽画。代码和菱形几乎一样,只是循环的起点和方向不同。

🧠 对比学习:把沙漏和菱形的代码并排放在一起对比。你会发现:它们只是"谁先画、谁后画"的顺序不同。学会对比,你就学会了举一反三。

Python
14
准备加载编辑器...
🔧 正在准备编程环境...0%
等待编辑器...
等待 Python 环境...

9.5 趣味挑战:动态进度条

把学到的知识组合起来——做一个会"动"的进度条:

Python
14
准备加载编辑器...
🔧 正在准备编程环境...0%
等待编辑器...
等待 Python 环境...

💡 设计思路:进度条的秘诀是 print(f"\r{bar}", end="")\r 让光标回到行首(不换行),end="" 禁止自动换行——这样每次循环都覆盖同一行,就产生了"动画"效果!

⚠️ 常见误区:如果你忘记写 end=""print() 会自动换行——你会看到 50 行进度条而不是"原地更新"的一条!另外,time.sleep(0.1) 只是为了让动画慢一点,实际运行中可以省略。

🧪 试试看:把 total 改成 100,体验更细腻的进度条。你还能在进度条上加上时间预估吗?比如"预计还需 X 秒"。


9.6 字符画——emoji 也能作画 🖼️

从图案到艺术 🎭

前面的图案都是"算"出来的(用循环一行一行生成),但有时候最简单的方式是直接画——就像用字符拼贴画。

注意这段代码的 cat 是一个列表,每一行是一个字符串。这告诉我们:换一种数据结构(列表而非循环),就能换一种创作方式

Python
14
准备加载编辑器...
🔧 正在准备编程环境...0%
等待编辑器...
等待 Python 环境...

🧪 试试看:你能用字符画一只狗吗?或者一架飞机、一艘火箭?把图案存在列表里,然后用 for line in drawing: print(line) 输出——就这么简单!


🎨 设计你的专属图案

在进入终极挑战之前,花两分钟想象一下:如果你能"打印"出任何图案,你最想画什么?

这里有一个设计模板,帮你从想法到代码:

第一步:在草稿纸上画出图案(最多 7-8 行,以免太长)
第二步:把每一行翻译成字符串(空格 + 字符)
第三步:放到列表里,用一个 for 循环打印

💡 创意提示:除了 emoji,你还可以用以下字符组合:

  • O. 画人脸

  • |- 画边框

  • _/\ 画立体感

  • 中文「口」「田」「十」画像素画


9.7 终极挑战:自定义图案生成器

抽象的力量 💡

前面每个图案都写了专属代码,但你有没有发现:三角形、菱形、正方形……它们的"骨架"其实是一样的——都是两层循环,一层控制行,一层控制列

能不能写出一个通用函数,一个 draw_shape() 搞定所有形状?这就是"抽象"的力量——找到不同事物背后的共同规律,用一个公式解决一类问题。

Python
14
准备加载编辑器...
🔧 正在准备编程环境...0%
等待编辑器...
等待 Python 环境...

💡 发挥创意:改 char 参数,试试 "❤️""🎵""👾"……甚至可以用 "AB" 等字母!你的想象力是唯一的限制。

🏆 终极挑战:给 draw_shape() 添加一个"反转"参数 reverse=True,让图案上下颠倒!提示:条件分支 + 颠倒循环方向(reversed(range(...)))。

🧪 更多试试看

  • draw_shape("菱形", 8, "🌟") 画一颗闪亮的大钻石

  • draw_shape("三角形", 3, "🔥") 画一团小火焰

  • 试试在"正方形"模式下输出一个棋盘格(隔行交替两种字符)

⚠️ 常见误区总结:回顾这一章,最容易犯的三个错误:

  1. 索引从 0 还是从 1 开始? — 先确定 range() 的起始值,再调整公式

  2. 空格和字符的顺序? — 先空格(让图案居中),再字符(图案本身)

  3. 下半部分的循环方向? — 菱形下半区用 -1 递减,沙漏下半区用递增——方向错了图案就反了


🎯 从代码到艺术:当循环遇上字符串,代码就是最好的画笔。这些看似简单的图案,背后是循环逻辑的深刻理解——每一次内层循环和外层循环的配合,都在创造规律之美!

🎨 你的作品集:恭喜你完成了"字符画术"的全部修炼!现在你手里的画笔不只是 print()——你还学会了"算"图案(循环法)、"拼"图案(列表法)、"抽象"图案(函数法)。去画室里自由创作吧,说不定下一个 ASCII 艺术大师就是你!