资讯动态

自学编程第十八天:用Python写一个通讯录命令行工具,踩坑与复盘

发布时间:2026/10/4 4:08:25 来源:尧图企业网站定制
今天是开始自学IT的第十八天。三个星期前我还分不清Python和“蟒蛇”有什么关系现在居然能独立写一个带命令行交互、能保存数据到文件的小工具了。这种转变谈不上多厉害但它让我第一次对“坚持”这两个字有了实感——特别是当你处在最容易放弃的第三周身边没人指导、网上课程越囤越多、自己写的代码一运行就报错能继续往前挪一步都算是胜利。这篇文章是我第十八天学习记录的完整复盘内容包括当天的学习目标、具体代码示例、踩过的三个典型坑、以及我调整过后的学习方法。如果你也在自学编程或者正准备开始学希望这份记录能让你少走一点弯路。毕竟自学的路上最难的不是找不到资源而是找不到一个真实的人告诉你这一步会卡住很正常原因是这样的。1. 自学第十八天的整体状态与学习计划1.1 为什么第十八天是个关键节点很多人把自学计划定在“21天”但真正体验过的人都知道第十天到第二十天才是淘汰率最高的一段。第一天和第二天全是新鲜感第五天还能靠热情撑着到了第十八天热情基本烧完了习惯又没有完全养成。你会开始怀疑自己是不是材料不够、智商不够、还是压根就不适合走这条路。我的第十八天正好卡在这个节骨眼上。前一天晚上我学完了一段关于函数定义的视频课听得懂但关上屏幕后什么都写不出来。那种“眼睛会了、手不会”的感觉非常消耗信心。所以第十八天我临时调整了策略不看新视频不学新语法只做一件事——用已经学过的内容硬写一个完整的小项目。这个决定带来一个很直接的变化当我不再被“下一个知识点”追赶时注意力终于能放在“把代码写对”上。以前看视频时觉得函数、字典、循环这些概念都很简单自己动手才发现把它们组合在一起会出现无数个之前没见过的错误。第十八天恰好是检验基础是否扎实的好时机如果拖到一个月后再来补基础代价会大得多。1.2 当天的学习目标拆解早上我先用十五分钟列了当天的目标没有贪多只定三件事复习函数定义与调用特别是参数传递的细节复习字典的增删改查操作并练习多层嵌套把前面学过的知识串成一个完整的命令行通讯录程序。这三件事看起来不多但实际操作下来从早上九点到中午十一点半我连代码带查错一共用了两个半小时。中途一度想放弃但最终还是把它跑通了。事后复盘我觉得目标拆解得越具体越好比如“今天学会字典”这种目标基本等于没定因为字典牵扯到增删改查、遍历、嵌套、默认值任何一个细节卡住都会让你觉得“没学会”。把目标细化成“用字典实现联系人的新增和删除功能”你才知道今天到底有没有完成任务。2. 今天敲的核心代码一个联系人管理小工具2.1 功能设计与伪代码写代码之前我先在纸上画了一下这个工具大概长什么样。很多初学者习惯打开编辑器就噼里啪啦敲代码结果敲到一半发现逻辑理不清又全部删掉重来。我的做法是先写伪代码把流程固定住再动手实现。这个联系人工具的需求很简单用户可以在终端里输入命令完成以下操作——添加联系人、查看所有联系人、修改联系人的电话号码、删除联系人最后还要能把数据保存到本地文件里下次打开时不会丢。对应的伪代码如下循环显示菜单 1. 添加联系人 2. 查看联系人 3. 修改联系人 4. 删除联系人 5. 保存并退出 用户输入选项后执行对应操作伪代码写完后我心里大概有数了整体结构要用while True来维持菜单循环每个操作分别定义成函数所有联系人数据用一个字典来保存键是姓名值是电话号码。结构定了之后代码写起来就没那么慌。2.2 完整代码与运行效果下面是我当天写的完整代码虽然和网上那些优雅的示例有差距但这是我自己一步一步调出来的版本import json contacts {} def add_contact(): name input(请输入联系人姓名) if name in contacts: print(联系人已存在如需修改请选择修改功能。) return phone input(请输入联系电话) contacts[name] phone print(f已添加联系人{name}) def show_contacts(): if not contacts: print(通讯录为空。) return for name, phone in contacts.items(): print(f{name}: {phone}) def update_contact(): name input(请输入需要修改的联系人姓名) if name not in contacts: print(联系人不存在。) return new_phone input(请输入新的联系电话) contacts[name] new_phone print(f已更新 {name} 的电话号码。) def delete_contact(): name input(请输入需要删除的联系人姓名) if name not in contacts: print(联系人不存在。) return del contacts[name] print(f已删除联系人{name}) def save_to_file(): with open(contacts.json, w, encodingutf-8) as f: json.dump(contacts, f, ensure_asciiFalse, indent4) print(通讯录已保存到 contacts.json) while True: print(\n 通讯录管理 ) print(1. 添加联系人) print(2. 查看联系人) print(3. 修改联系人) print(4. 删除联系人) print(5. 保存并退出) choice input(请输入操作编号) if choice 1: add_contact() elif choice 2: show_contacts() elif choice 3: update_contact() elif choice 4: delete_contact() elif choice 5: save_to_file() break else: print(无效输入请重新输入。)运行效果大概是这样的 通讯录管理 1. 添加联系人 2. 查看联系人 3. 修改联系人 4. 删除联系人 5. 保存并退出 请输入操作编号1 请输入联系人姓名张三 请输入联系电话13800138000 已添加联系人张三代码写完的那一刻我确实挺兴奋的因为这是第一个能“存住数据”的程序。但后来我也发现了它的问题比如没有异常处理、没有输入校验、数据量大了以后不好查。可对我来说第十八天能跑通这个意义在于我把学过的内容真正用了一次而不是继续对着屏幕看别人演示。3. 今天踩过的坑与排查实录3.1 编码问题中文乱码并不都是代码的错第一个让我抓狂的问题发生在保存文件时。我用open()写入联系人数据最开始没有指定encoding在 Windows 终端里运行的时侯中文全部变成了乱码。我把代码来回改了好几遍最后才反应过来问题不在于代码逻辑而在于文件读写默认编码和终端编码不一致。解决办法是在打开文件时明确指定编码with open(contacts.json, w, encodingutf-8) as f: json.dump(contacts, f, ensure_asciiFalse, indent4)这个坑给我最大的教训是遇到中文乱码先分清是终端显示乱码还是文件存储乱码。如果是终端显示乱码可以在代码开头加一行# -*- coding: utf-8 -*-或者调整终端代码页如果是文件内容乱码基本就是读写时编码指定不一致。当时我把encodingutf-8加到读取和写入两处之后问题彻底解决。3.2 默认参数陷阱数据串味的真正原因我后来还踩了一个非常隐蔽的坑。为了一些提示信息我写了一个类似这样的函数def add_tag(tag_list[]): tag_list.append(新标签) return tag_list第一次调用没问题第二次调用时返回的列表里莫名多出了上一次的数据。奇怪的是这个列表里的数据不会被多次添加。查了很久才发现Python函数的默认参数是在定义时创建的同一个列表对象会一直被使用。解决办法是使用不可变值作为默认参数或者干脆传入None在函数内部再创建列表def add_tag(tag_listNone): if tag_list is None: tag_list [] tag_list.append(新标签) return tag_list这个坑对初学者来说特别容易踩因为语法上完全合法逻辑上却和直觉相反。我个人现在写函数时已经习惯检查所有默认参数凡是可变类型一律不用。3.3 变量作用域局部变量为什么“变没了”第三个坑出现在我修改联系人信息时。函数里我写了一段更新电话号码的逻辑运行后发现通讯录里的数据根本没变。后来我才意识到问题出在一个同名的局部变量上。我在函数内部对变量赋值时Python会默认把它当成一个新的局部变量除非我显式声明要修改全局变量。虽然在这个小工具里我很快意识到不用函数修改全局变量更好但更合理的做法是让函数接收一个字典参数然后修改这个字典的内容。因为字典是可变对象函数内部修改字典外部也会跟着变def update_phone(count_dict, name, new_phone): count_dict[name] new_phone这个思路也解决了后面一个问题当我学会分模块写代码之后经常会因为全局变量太多导致调试困难用传参的方式反而更好维护。4. 自学习惯与效率方法论复盘4.1 从被动看视频到主动写笔记第十八天结束后我对学习方法有了一个明显的调整。前半个月我主要在看视频看的时候觉得自己全会实际上手就废。这不是某个人的问题而是视频学习天然有“被动接收”的特点大脑很容易产生已经在学会了的错觉。后来我改成了“视频只看50%剩下50%用来写笔记和做练习”。看视频每讲完一个知识点我会暂停然后把代码抄一遍自己解释一遍。重点不是把代码背下来而是搞清楚每一行在原知识体系里的位置。比如学到函数参数时我给自己写了一个小卡片记录位置参数、默认参数、可变参数的区别并用表格对比参数类型定义写法调用方式常见坑位置参数def f(a, b)f(1, 2)顺序不能错默认参数def f(a, b3)f(1)可变值不能当默认参数可变参数def f(*args)f(1, 2, 3)得到元组不是列表这种笔记方式帮我把脑子短暂记住的内容留在了纸面上。现在翻看前几天的笔记很多当时一知半解的地方已经自然理解了。4.2 最小反馈闭环写代码、看报错、修bug、做记录我还给自己定了一个“最小反馈闭环”原则用四个步骤循环写一小段代码只做一件事运行它故意让它报错或者观察输出是否符合预期如果出错先读最后一行错误信息再往上追代码修复后把问题和解决思路记录到当天的日志里。这个习惯帮了我大忙。以前一看到报错就慌动不动全屏截图求助。后来发现大多数错误信息都有固定的套路比如NameError说明变量没定义、TypeError说明类型不对、IndexError说明越界。读到错误类型后再去查具体行数效率高多了。第十八天那天我记录的一个典型错误是KeyError: name当时我以为是字典的问题后来才发现是数据文件里根本没有这个键。为了排查我在程序里临时加了一行调试输出print(contacts.keys())看到输出结果后真相一目了然。我现在遇到奇怪的问题第一反应不是找大神而是先打印出来看看数据到底是什么样。很多时候问题只是存在信息和理解不一致。5. 下一步学习规划与给同类自学者的话5.1 面向对象和第二遍重构第十九天开始我准备进入面向对象的学习。但我给自己定了一个不一样的目标不是看完面向对象的视频课而是把通讯录小工具用面向对象的方式重写一遍。也就是说把现有的函数式代码改造成用类来组织逻辑。用一个ContactBook类来管理所有联系人把之前散落的函数变成类的方法。这样做的原因很简单语法只是表面真正要理解面向对象必须亲自动手把一个已经能跑的项目改造一遍。改造过程中会遇到很多新问题比如对象的属性怎么设计、方法之间怎么共享数据、类变量和实例变量有什么区别。这些问题光靠看视频解决不了但如果你在重构中遇到它们再回去看视频理解会完全不一样。我给自己规划了接下来七天的方向天数学习主题练习目标第十九天类与对象基础为通讯录写一个ContactBook类第二十天继承与会话实现一个更复杂的命令行交互逻辑第二十一天文件读写进阶用 CSV 格式导出通讯录第二十二天异常处理为所有输入操作添加异常处理第二十三天小型项目重构把通讯录工具改造得可用、规范第二十四天单元测试入门为通讯录写几个简单的测试用例第二十五天学习复盘把前几天的成果整理成项目总结这个计划不一定适合所有人但对我来说它解决了“下一步不知道学什么”的焦虑。每天都有一个明确的终点哪怕进度慢一点也比东一榔头西一棒子强。5.2 给同样自学的朋友几句大实话第十八天那天晚上我坐在书桌前复盘脑子里冒出来几句话可能对同样走在自学路上的人有点帮助。第一不要和别人比进度。我在一些论坛里看到有人十五天就学完了别人一个月的内容心态差点崩了。后来想通了自学是长跑不是短跑。别人学得快和你没关系你学得慢也不代表最后走不到终点。第二一定要动手敲代码。看视频、看别人写的代码示例和自己从空白文件开始写难度差了不是一点半点。哪怕只是照着示例敲一遍也比光看强十倍。第三报错不是坏事。第十八天之前我一看到Traceback就头大觉得是自己不行。后来才意识到每个报错都在告诉我代码的哪一行出了问题这比我满屏逻辑错误却没有任何提示要友好得多。把报错当成老师的批改心态就顺了。第四不用囤资料。我的网盘里躺着十几个教程、几十本电子书真正看完的不到两本。到现在我终于明白教程的作用只是把人领进门真正能让你进步的是不断写代码、不断解决问题的循环。把一套资源吃透远胜于收藏十套。第五允许自己有学不会的地方。第十八天我仍然搞不懂装饰器的原理也不理解 Python 的 GIL 到底是怎么回事。但没关系这些大概率不会影响我继续往前走。把暂时用不到的知识放到“待学习清单”里等真正需要的时候再回来专攻效率往往更高。自学第十八天我依然谈不上什么 IT 从业者但至少我不再像刚开始那样觉得编程是一门玄学。它是有规律可循的是一步一步的工程过程。第天写几行代码、修几个 bug、记几条笔记把时间拉长你会看到一个肉眼可见的进步曲线。这就是我第十八天最大的收获。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑