1024程序员节学习复盘
1024程序员节
今天跟着“1024程序员节”的课表开始学 Python。上午的进度虽然只推进了两节(复习基础语法 + 函数)为了防止自己“学了就忘”,我把上午的踩坑记录和知识理解整理了一下。
一、 被 while 和 break 折磨
今天写的第一个完整程序是“重启终端:口令 1024 。代码虽然不长,但我调了好几次。
下面是我写的打卡器:
1 | check_count = 0 |
最后那句可以不写的,就是看起来更美观一点
给自己记下的两个教训:
- check_count = 0 必须写在 while 外面! 我今天才彻底搞懂,如果把这个记分牌写在 while 里面,每次循环一开始,分数就被强行清零了,永远也攒不够 3 次 。
- 不加 break 就是是个死循环。 while True 是个无底洞,如果我不写 break 去结束它,即使输入了 exit ,程序也会继续问我 请输入学习内容 。
二、 懂了,但没完全懂的函数(参数和返回值)
上午重点学了 def 定义函数。我把函数整合到了打卡器里,写了进阶版的代码:
1 | def calculate_exp(times): |
我们总说“定义一个函数”,我查了一下其实代码里的 def 就是英文 define(定义)的缩写。
那函数又是什么:你放进去 参数 ,按下启动键 执行代码,最后出来了 返回值 。它最大的好处就是把一堆干活的代码“ 打包 ”起来,起个名字,以后需要用到的时候,喊一声名字就行了,不用重复写。
- def :给电脑下达“造机器”的指令。
- calculate_exp :给这个机器起的名字(以后叫名字就能用它)。
- ( times ):机器接收参数的地方,得往里面塞个东西,机器才能运转。
- :(冒号):这个很重要,它相当于宣告:“ 机器内部的构造说明书,从下一行开始!”所以下一行必须要缩进。
我理解的 :原来 def 只是在“画图纸”和“造机器”。只要电脑没看到你 “ 按开关 ”(也就是没看到你调用 calculate_exp(3)),这台机器造好了也只会静静躺在那里,根本不会自己跑起来。只有调用它,它才会开始工作。
脑补:print 和 return 到底差在哪?
这是上午最卡我的地方。我还以为写个函数让它打印出来就完事了,今天才明白:
- return 是交还结果:函数算完账,用 return 把数据悄悄塞回给外面的变量( my_exp ),这一步在屏幕上是看不见的。
- print 只是让你看个响:外面拿到了 my_exp 这个数据后,我再写个 print,屏幕上才会出现“获得经验值”。
总结 :没 return,外面的程序就接不到数据;没 print,我就看不到结果。
三、 实战做题:
上午做了一道限时题:算算距离 1024 经验差多少,如果超额了就输出 0,且要求不要打印任何提示语。
我提交的正确代码(后面还有翻车操作):
1 | # 1. 接收输入:题目要求不要任何提示语,直接接收并转成整数 |
第一步:接收输入
题目要求 “ 输入一个非负整数 ” ,然后题目是说:“不要打印任何提示语”。
所以,代码不能写 input(“请输入…:”),只能写:n = int(input())
第二步:算差值
题目说“每完成一道题获得 32 点经验”,那目前的经验就是 n * 32。目标是要攒够 1024 点经验,那距离目标还差多少呢?
就是拿总分减去当前分:1024 - (n * 32)。我把这个算出来的差值装进一个变量里,叫它 diff:
diff = 1024 - n * 32
复盘时的反思:现在我觉得叫 task_count 更好
我上面交上去的代码里,变量用的是 n。这是数学题的老习惯,我当时图省事就写了。
但现在写这篇复盘博客时,我越看越觉得不对劲。代码不仅是给电脑跑的,更是给人看的。n 过几天我自己可能就忘了是啥意思。
如果把它起名叫 task_count( 任务数量,也可以理解成题目数量 ),一眼就能看出这是“ 完成的题目数量 ”,可读性强多了。
第三步:判断输出
题目要求:如果还没达到,输出差值;如果达到或超过了,输出 0。
这时候就要看 diff 的值了:
· 如果 diff > 0:说明还没到 1024,那就直接输出差值。
· 如果 diff <= 0(也就是 else):说明不仅到了,还可能超额了(差值是负数或者0),题目要求这种情况输出 0,那就直接 print(0)。
总结一下我的思考:
刚开始做题时,我容易在“大于、小于”里面绕进去(这也是我踩坑第 3 点写的,看别人写成 if diff >= 1024 直接绕晕了)。
后来我想明白了:我只要关心“还差多少(正数)”就行了,至于超过的部分,题目说不用管,直接给个 0 就行。
运行时我的翻车操作:
1. 输入空回车会死机 :我运行测试的时候手欠,直接按了回车,结果报错,具体它写的什么不记得,但是大概意思就是:int( ) 遇到空字符串(空气)直接罢工了。以后测试这种题,千万不能习惯性按回车。
2. 不要乱加提示语:平时习惯写 input(“请输入…”),但是系统它只认纯数字。
3. 逻辑差点写反:差值是 1024 - 得分。如果超额完成,这个差值就是负数。所以判断是否输出 0,条件是 if diff <= 0 或者像上面那样 if diff > 0 走正常流程。看别人代码时,发现有人写成了 if diff >= 1024,逻辑直接就绕进去了。
四、数据结构:把数据管起来(列表与字典)
下午学了字典(Dict)和列表(List)
- 字典 :用大括号 { } 包起来,左边是键(Key),右边是值(Value)。
- 我犯的错 :一开始把年龄写成了 ‘year’ : ‘19’(加了引号变成了字符串)。以后要是拿年龄做加减法计算,绝对会报错,数字千万别加引号。
先看一段最基础的代码,感受一下:
1 | # 1. 创建一个字典 |
用下来我觉得字典最好用的地方在于,它能用一个“名字(键)”直接找到对应的“东西(值)”。而且它是可变对象,我们可以随时修改里面的数据,这在做身份卡、存用户信息时非常方便。
菜单循环与功能拆分
然后这是我课上写的代码分解:
1 | # 1. 用字典存储个人身份信息 |
为什么 my_info 要写在外面?
因为它是“全局”的数据。
1 | # 2. 功能函数:封装展示个人名片的逻辑 |
为什么要单独写一个 show_card 函数?
因为不封装成函数,每次用户输入 check ,我们都要把上面这几行 print 重新写一遍。封装成函数后,主程序里只要一句 show_card(my_info) 就能直接调用,代码更干净。这就叫“封装”。
1 | # 3. 主程序:命令行交互循环 |
讲讲 while True 的感觉。就是可以比喻说:“这就好比我开了一家店,只要顾客没喊 exit(关门),我就一直坐在这里等他们输入指令。”
看着这三段代码,最大的感受就是“逻辑其实不难,就是把生活搬进代码里”。字典就是我的身份档案,函数就是我的展示卡片动作,while 循环就是我在等你跟我说话。
列表在代码里怎么用(简洁了一点):
在代码分解1里面,最后一个代码后面,加上 'skills': ['Python', '写代码', '找Bug']。在“代码分解2”里面倒数第二行,加上 print(f"技能:{info_dict['skills']}")。
理解 :为什么要在字典里塞一个列表?
- 在写“ 个人信息卡片 ”的时候,我发现“爱好”通常只有一个(比如敲代码),用字符串就够了。但是“技能”往往有多个。
- 如果我把技能写成 ‘skills’: ‘Python, 写代码, 找Bug’,它本质上还是一个长字符串,以后如果我想单独把 Python 挑出来,就很麻烦。
- 所以我用了一个列表 [‘Python’, ‘写代码’, ‘找Bug’] 作为字典的值。这就是今天学到的(字典套列表)。当程序打印 info_dict[‘skills’] 的时候,它会原封不动地把整个列表展示出来。这样写,方便以后随时添加新技能。
五、让程序拥有记忆与容错能力(with open)
前面的终端,只要一敲 exit 数据就全丢了,而且用户要是乱输入还会直接崩溃。为了解决这两个问题,我用了两段代码来巩固 with open 和 异常处理。
怎么理解 with open 这几个词?
- open:就是“打开文件”。
- as f:给打开的文件起个外号叫 f。接下来读(f.read())或者写(f.write()),直接喊 f 就行。
- with:这是最核心的词。有了它,就完全不用写 f.close( )。只要代码退出了 with 的缩进范围,不管中间有没有报错,它都会保证把文件安全关上。
1. with open:这到底是啥?
这是以前的“ 非优雅 ”写法(容易漏内存):
1 | f = open("笔记.txt", "r", encoding="utf-8") |
不好在哪? 如果 f.read() 的时候代码突然报错崩溃了,程序直接中断,根本走不到 f.close() 这一步。结果就是文件被占用,造成内存泄漏。
这是现在的“ 优雅 ”写法(with open):
1 | with open("笔记.txt", "r", encoding="utf-8") as f: |
2. 用 mode=“a” 写一个极简“ Bug记录仪 ”
懂了 with open 之后,我写了一个极简版的代码,把灵感追加存进 txt 文件里:
1 | content = input("请输入你的灵感: ") |
复盘:
- 之前学的是 mode=“w”( 覆盖写入 ),只要用 “w”,以前写的东西就全没了。
- 这次用了 mode=“a”(追加),它就像翻到笔记本的下一页接着写,之前的记录稳稳保留。这就是让程序拥有“ 记忆 ”的基础。
结合课上的截图,我发现 open 函数其实大有学问。它不仅仅是一个 “ 打开 ” 动作,里面还有好几个关键参数:
1 | # 优雅写法完整版 |
这行代码里包含了这几个关键点:
1. 文件路径 :
课上的笔记写了这两个概念,我一开始也绕晕了,后来用快递地址和指路来理解,瞬间就通了:
绝对路径 :( 像写快递地址 )
- 概念:从电脑的“盘符”(比如 C盘、D盘)开始,一直写到你想要的文件名,一步都不落下。
- 代码示例:C:\Users\1\Desktop\today\test\test2.txt
我的理解:就像寄快递,必须写明“中国-江西省-南昌市-某某区-某某路-某某小区-几栋几号”。不管你人在哪里,只要拿到这个完整的地址,就一定能找到目标。
相对路径: ( 像在家里指路 )
概念:以你当前运行的代码文件所在的位置为起点,去找到目标文件。
代码示例 :
- 如果文件和代码在同一个文件夹里,直接写文件名就行:“test2.txt” 。
- 如果在代码文件的上一级目录,写:“…/test2.txt” 。
我的理解:就像你在家里坐在沙发上,跟室友说 “ 去厨房拿个苹果 ”。你不需要说 “ 去地球上中国某某小区的厨房 ”,因为室友(电脑)知道你现在就在家里(当前代码目录),它顺着你的位置去找厨房就行。
- 注意 :Windows 路径里有反斜杠 \,为了防止被识别为转义字符(比如 \n),前面一定要加个 r(代表 raw string)。
2. 编码 (encoding):
- 一定要写 encoding=“utf-8” 。如果电脑默认用 GBK ,读中文就会乱码。
- 为什么一定要写? 记得课上学长说的:计算机底层只认识 0 和 1,把中文变成 0 和 1 的规则就叫 “ 编码 ”。不同系统默认的编码不一样(这是我查的Windows 经常默认是 GBK,而 Mac/Linux 默认是 UTF-8)。
- 乱码:如果不指定 encoding=“utf-8”,写进去的中文在别人的电脑上打开可能全是一堆问号或者“锟斤拷”。
- 结论:只要写文件,无脑加上 encoding=“utf-8”
3. 模式 (mode):
这是最核心的参数,决定了你打开文件后能干嘛:
- mode=“r”(只读模式,默认): 只能看,不能改。如果文件不存在,程序会直接报错 FileNotFoundError。
课后补充:带 + 和 b 的模式:
- r+、w+、a+ :代表既能读又能写。
- rb、wb :代表以二进制模式读写。如果要处理图片、视频、音频这些非文本文件,就必须用带 b 的模式,且不能指定 encoding 。
总结:
平时写代码,如果能用相对路径(比如就直接写 “log.txt”)就用相对路径,因为代码挪到别的电脑上也能直接跑。
如果实在找不到,或者必须用绝对路径,记得在 Windows 下加个 r 防转义
基础异常处理:
有了文件操作还不够,如果用户乱输入,程序还是会崩溃。我写了个“成绩查询系统”来练习 try 和 except 。
1 | scores = {"语文": 91, "数学": 90, "英语": 77} |
结合我的成绩查询代码,它的运行逻辑是这样的:
1. try(尝试区):
1 | subject = input("请输入科目: ") |
我告诉电脑:“ 你先试着执行这两行代码 ”。如果我输入了“ 数学 ”,字典 scores 里面有,电脑顺利打印出成绩。
2. except KeyError(兜底区):
如果我手欠,输入了“ 物理 ”或者“ 体育 ”或者其他什么,字典里根本没有这个键。按照以前的脾气,电脑会直接爆红报错(KeyError),程序当场死机。
但现在我写了 except KeyError: 这就相当于告诉电脑:“如果你遇到了找不到键(KeyError)的错误,别死机,来执行我这里的代码。”所以它会温柔地打印一句:“ 没有找到该科目的记录 ”。
3. else(顺利区):
1 | else: |
只要 try 里面的代码没有发生任何报错,顺利跑完了,它才会接着执行 else 里面的代码。
我的脑补 :
以前只要我输入错东西,程序直接一片爆红死机。现在有了 try 和 except:
- try 就是 “ 你试着跑一下 ”。
- except KeyError 就是 “ 如果报了这个错,我来接住 ”。
- else 是 “ 如果一切顺利,最后打印这句话 ” 。
这样程序就有了容错能力
六、 限时挑战赛:B题与C题复盘
在做完前面的终端后,我挑战了下面两道题。这两道题让我对“枚举”和“基础复杂度”有了深刻的体会。
C题:连续打卡
题目大意:输入一个只包含 0 和 1 的字符串(1代表打卡了),求最长连续 1 的长度。
示例:输入 11011101,输出 3。
思路拆分:
题目给的提示非常有用:“ cur 记当前连续几个 1,best 记历史最长 ”。
这就像打游戏,cur 是你当前的连杀数,best 是你本局的最高连杀记录。一旦死了一次(遇到 ‘0’),cur 就归零了,但 best 会永远记住你最辉煌的时刻。
我的代码:
1 | s = input() |
B题:寻找节日数字
题目大意:输入一个整数 n,统计 1 到 n 之间,包含字符 ‘4’ 的整数有多少个。
示例:输入 50,输出 14(因为 4, 14, 24, 34, 40~49 里面都有 4)。
思路拆分:
一开始我想得很复杂,去算个位、十位是不是 4。但题目提示直接把我看傻了:“把数字变成字符串,用 “4” in str(i) 就能判断”。
对哦,用 str(i) 把数字变成文本,然后直接看 “4” 在不在里面。
至于我看课表里说的 “ 基础复杂度 ”,题目里有一句话:“1 到 100000 共 10 万次判断,对电脑来说是眨眼的事。” 我觉得数 10 万个数要累死,但对 CPU 来说,连一秒钟都不用🤡。
我的代码:
1 | n = int(input()) |
总结:
这两道题让我明白了,写程序不需要像人脑那样去 “ 硬算 ”。
- 遇到数数的问题,用 for 循环去枚举(一个个试)就行了,电脑最不怕的就是重复劳动。
- 遇到判断包含的问题,把数字转成字符串去查找,往往是会比数学公式更简单的。
- 这两道题的代码都没有超过 10 行,但解决的都是非常实际的问题。
