基础项目练习
学完前面的变量、条件、循环、函数、列表、字典、文件以后,只停留在“看懂例子”是不够的。真正能不能把知识点用起来,要看你能不能独立完成一个小项目。
这一节不给你讲新语法,而是带你把前面学过的东西串起来,做一个真正能运行的小工具。你做完这个项目以后,应该能明显感受到:原来代码不是一行一行孤立存在的,而是可以组合成一个完整功能。
本节目标
- 学会把多个基础知识点组合成一个完整程序
- 学会先拆需求,再写代码
- 学会用函数组织程序结构
- 学会把结果保存到文件
- 学会排查运行中的常见错误
先修知识
在开始之前,你至少应该已经掌握这些内容:
- 变量、输入与输出
if条件语句for和while循环- 列表和字典
- 函数
- 文件读写
如果上面这些你还不熟,建议先回去把前面的章节复习一遍,再来看这一节。因为项目练习不是新的知识点堆积,而是旧知识点的综合应用。
为什么零基础一定要做项目
很多初学者有一个典型问题:单独一页一页看文档时,好像都懂;真到自己写代码时,脑子却是空的。
这不是因为你不聪明,而是因为你还没有建立“程序结构感”。
所谓结构感,就是你看到一个需求时,能立刻想到:
- 先准备什么数据
- 要做哪些判断
- 哪些操作要重复执行
- 哪些逻辑适合写成函数
- 最终结果要输出到屏幕,还是写入文件
项目练习的意义,就在于帮助你从“会看代码”走向“会自己组织代码”。
练习项目:图片链接整理器
我们先做一个适合零基础的项目:图片链接整理器。
这个项目的目标很简单:
- 准备一批图片链接
- 去掉空字符串和重复链接
- 给每个链接编号
- 判断链接是否是常见图片格式
- 把整理结果输出到屏幕
- 再保存到本地文本文件
你会发现,这个项目虽然小,但已经把很多基础知识点都串起来了。
第一步:先把需求翻译成代码任务
遇到需求时,不要立刻开始写代码。先把需求拆开。
这次的需求可以拆成下面几步:
- 用列表保存一批原始链接
- 遍历列表
- 跳过空值
- 判断是否重复
- 判断扩展名是否像图片
- 生成整理后的结果
- 打印输出
- 写入文件
只要你会拆,代码就不会乱。
第二步:准备原始数据
先写一批模拟数据。真实项目里这些数据可能来自网页、数据库、接口或者用户输入,但在练习阶段,我们先把它写死在代码里。
raw_urls = [
"https://img.example.com/a.jpg",
"https://img.example.com/b.png",
"",
"https://img.example.com/a.jpg",
"https://img.example.com/c.gif",
"https://img.example.com/readme.txt",
"https://img.example.com/d.jpeg"
]
print(raw_urls)输出结果:
['https://img.example.com/a.jpg', 'https://img.example.com/b.png', '', 'https://img.example.com/a.jpg', 'https://img.example.com/c.gif', 'https://img.example.com/readme.txt', 'https://img.example.com/d.jpeg']这里我们故意放了几种情况:
- 正常图片链接
- 空字符串
- 重复链接
- 非图片文件链接
这样后面写逻辑时,效果会更明显。
第三步:先写一个判断函数
当你发现某个判断逻辑可能会重复使用时,就应该考虑写成函数。
例如这里我们要判断一个链接是否是图片链接,可以写成这样:
def is_image_url(url):
image_suffixes = [".jpg", ".jpeg", ".png", ".gif", ".webp"]
for suffix in image_suffixes:
if url.endswith(suffix):
return True
return False
print(is_image_url("https://img.example.com/a.jpg"))
print(is_image_url("https://img.example.com/readme.txt"))输出结果:
True
False这里的核心点有两个:
endswith()用来判断字符串是否以某个内容结尾- 只要匹配到一种图片后缀,就立刻
return True
如果循环结束都没有匹配成功,最后再 return False。
第四步:去空、去重、过滤非图片链接
现在开始处理主逻辑。
raw_urls = [
"https://img.example.com/a.jpg",
"https://img.example.com/b.png",
"",
"https://img.example.com/a.jpg",
"https://img.example.com/c.gif",
"https://img.example.com/readme.txt",
"https://img.example.com/d.jpeg"
]
def is_image_url(url):
image_suffixes = [".jpg", ".jpeg", ".png", ".gif", ".webp"]
for suffix in image_suffixes:
if url.endswith(suffix):
return True
return False
clean_urls = []
for url in raw_urls:
if url == "":
continue
if url in clean_urls:
continue
if not is_image_url(url):
continue
clean_urls.append(url)
print(clean_urls)输出结果:
['https://img.example.com/a.jpg', 'https://img.example.com/b.png', 'https://img.example.com/c.gif', 'https://img.example.com/d.jpeg']这段代码非常适合初学者反复看,因为它把基础语法都用到了:
for负责遍历if负责判断continue负责跳过不需要的数据in负责判断是否重复append()负责加入新元素
第五步:给结果编号
光有链接还不够,通常我们还希望给每条数据加一个序号,后面更容易查看。
clean_urls = [
"https://img.example.com/a.jpg",
"https://img.example.com/b.png",
"https://img.example.com/c.gif"
]
for index, url in enumerate(clean_urls, start=1):
print(f"{index}. {url}")输出结果:
1. https://img.example.com/a.jpg
2. https://img.example.com/b.png
3. https://img.example.com/c.gifenumerate() 是一个非常常用的工具,它可以在遍历列表时同时拿到:
- 元素下标
- 元素本身
这里的 start=1 表示编号从 1 开始,而不是默认的 0。
第六步:整理成更完整的结果结构
如果以后你还想保存更多信息,比如文件类型、是否有效、来源页面,那么最好不要只保存一个字符串,而是保存字典。
clean_urls = [
"https://img.example.com/a.jpg",
"https://img.example.com/b.png",
"https://img.example.com/c.gif"
]
records = []
for index, url in enumerate(clean_urls, start=1):
record = {
"id": index,
"url": url,
"suffix": url.split(".")[-1]
}
records.append(record)
print(records)输出结果:
[{'id': 1, 'url': 'https://img.example.com/a.jpg', 'suffix': 'jpg'}, {'id': 2, 'url': 'https://img.example.com/b.png', 'suffix': 'png'}, {'id': 3, 'url': 'https://img.example.com/c.gif', 'suffix': 'gif'}]这样做的好处是,数据更有结构。后面你要打印、统计、写文件,都会方便很多。
第七步:把结果输出成更友好的格式
很多初学者写程序时,只知道 print(list)。这当然能看,但不适合实际查看。
我们可以把输出做得更清晰一点:
records = [
{"id": 1, "url": "https://img.example.com/a.jpg", "suffix": "jpg"},
{"id": 2, "url": "https://img.example.com/b.png", "suffix": "png"},
{"id": 3, "url": "https://img.example.com/c.gif", "suffix": "gif"}
]
for item in records:
print(f"编号:{item['id']}")
print(f"链接:{item['url']}")
print(f"格式:{item['suffix']}")
print("-" * 30)输出结果:
编号:1
链接:https://img.example.com/a.jpg
格式:jpg
------------------------------
编号:2
链接:https://img.example.com/b.png
格式:png
------------------------------
编号:3
链接:https://img.example.com/c.gif
格式:gif
------------------------------第八步:保存到本地文件
做工具类项目时,最终结果通常要落地保存。
records = [
{"id": 1, "url": "https://img.example.com/a.jpg", "suffix": "jpg"},
{"id": 2, "url": "https://img.example.com/b.png", "suffix": "png"},
{"id": 3, "url": "https://img.example.com/c.gif", "suffix": "gif"}
]
with open("image_urls.txt", "w", encoding="utf-8") as file:
for item in records:
line = f"{item['id']}\t{item['suffix']}\t{item['url']}\n"
file.write(line)
print("文件写入完成")输出结果:
文件写入完成文件内容示例:
1 jpg https://img.example.com/a.jpg
2 png https://img.example.com/b.png
3 gif https://img.example.com/c.gif这里你可以注意两个点:
\t表示制表符,可以让列之间看起来更整齐\n表示换行符,让每条记录独占一行
第九步:写成一个完整程序
前面我们是一小段一小段练习。现在把它们真正拼起来。
def is_image_url(url):
image_suffixes = [".jpg", ".jpeg", ".png", ".gif", ".webp"]
for suffix in image_suffixes:
if url.endswith(suffix):
return True
return False
def clean_image_urls(raw_urls):
clean_urls = []
for url in raw_urls:
if url == "":
continue
if url in clean_urls:
continue
if not is_image_url(url):
continue
clean_urls.append(url)
return clean_urls
def build_records(clean_urls):
records = []
for index, url in enumerate(clean_urls, start=1):
record = {
"id": index,
"url": url,
"suffix": url.split(".")[-1]
}
records.append(record)
return records
def show_records(records):
print("整理结果如下:")
for item in records:
print(f"编号:{item['id']}")
print(f"链接:{item['url']}")
print(f"格式:{item['suffix']}")
print("-" * 30)
def save_records(records, filename):
with open(filename, "w", encoding="utf-8") as file:
for item in records:
line = f"{item['id']}\t{item['suffix']}\t{item['url']}\n"
file.write(line)
raw_urls = [
"https://img.example.com/a.jpg",
"https://img.example.com/b.png",
"",
"https://img.example.com/a.jpg",
"https://img.example.com/c.gif",
"https://img.example.com/readme.txt",
"https://img.example.com/d.jpeg"
]
clean_urls = clean_image_urls(raw_urls)
records = build_records(clean_urls)
show_records(records)
save_records(records, "image_urls.txt")
print("项目执行完成")输出结果:
整理结果如下:
编号:1
链接:https://img.example.com/a.jpg
格式:jpg
------------------------------
编号:2
链接:https://img.example.com/b.png
格式:png
------------------------------
编号:3
链接:https://img.example.com/c.gif
格式:gif
------------------------------
编号:4
链接:https://img.example.com/d.jpeg
格式:jpeg
------------------------------
项目执行完成这就是一个完整的小项目了。它虽然不大,但已经具备“需求拆解 -> 编写函数 -> 处理数据 -> 输出结果 -> 保存文件”的完整流程。
这个项目用到了哪些知识点
你可以回头对照一下,看看前面的知识是怎么串起来的:
- 变量:保存链接、文件名、中间结果
- 列表:保存多条链接
- 字典:保存结构化数据
- 条件语句:判断空值、重复值、文件类型
- 循环:遍历原始数据和整理结果
- 函数:拆分不同功能
- 字符串方法:判断后缀、格式化输出
- 文件操作:保存最终结果
这就是项目练习最重要的意义:把“散着学”的知识点连起来。
常见错误
1. 把 = 写成 ==
下面这种写法是错误的:
if url = "":
print("空字符串")这里应该用 == 比较,而不是 = 赋值。
2. 没有给文件指定编码
如果你写文件时没有加 encoding="utf-8",某些系统环境下可能会出现乱码。
3. 忘记处理重复数据
如果你直接遍历原始列表然后写入文件,最后保存出来的内容可能会重复很多次。
4. 只会把代码全部堆在一起
很多初学者会把所有逻辑写在一个大 for 循环里。程序虽然也许能跑,但后面很难改、很难排错。你要慢慢养成用函数拆逻辑的习惯。
练习题
练习 1
把程序改成只保留 .jpg 和 .png 两种图片格式。
练习 2
在结果中新增一个字段 length,表示链接字符串的长度。
练习 3
统计一共有多少个 jpg、多少个 png、多少个 gif。
练习 4
让用户自己输入文件名,例如:
filename = input("请输入保存文件名:")然后把结果保存到用户指定的文件里。
练习 5
把这个工具改成“用户名整理器”“邮箱整理器”或者“网页标题整理器”,自己重新设计一套数据结构。
本节小结
这一节你没有学到新语法,但你学会了比“新语法”更重要的东西:怎样把基础语法组织成一个完整程序。
如果你能独立写完这个项目,并且完成上面的练习题,那说明你已经不只是“会看 Python”,而是开始进入“会用 Python”的阶段了。
接下来你再学函数、文件、数据库、爬虫时,就会更容易理解这些知识点为什么存在,以及它们在真实项目里到底怎么配合工作。