Python基础第二周:数据类型、控制流与函数避坑指南

发布时间:2026/10/24 5:51:20
Python基础第二周:数据类型、控制流与函数避坑指南 这几天把Python基础啃掉了第二块从变量和简单计算往深走了一步才发现写代码真正有意思的地方在于同样的语法不同人写出了截然不同的代码。这篇笔记想记录一下第二周的学习内容核心是数据类型、控制流和函数三大块。适合刚学完环境和基础语法的朋友也就是那种能跑通print(hello)、但还不太理解列表和元组到底差在哪的阶段的读者。我不打算面面俱到讲官方文档那样跟翻手册没区别。我想以我这周实际遇到困惑和查资料的经历为线索把关键知识点串起来顺便把踩过的坑写出来方便以后再翻。1. 数据类型先搞清楚Python里到底存的是什么1.1 整数与浮点数除法带来的第一个认知冲击之前我一直觉得数字就是数字做加减乘除还能有什么花样。直到我用Python算了个简单的除法7 / 2结果不是3是3.5这没问题但当我写7 // 2的时候结果是3地板除直接把小数部分砍掉了。刚看到这个结果确实愣了一下后来才明白这跟Python 3的除法设计有关系——单斜杠是真正意义上的除法返回浮点数双斜杠是整除向下取整。我试着把所有组合列了出来才发现这里面的门道比想象中多表达式结果类型10 / 42.5float10 // 42int-10 // 4-3int注意是向下取整10 % 42int-10 % 42int-10 // 4等于 -3 这件事我一开始怎么都想不明白明明 -2.5 向下取整怎么会是 -3后来才理解floor的意思是往更小的方向取-3比-2.5小所以取 -3。这个特性在写算法、处理循环索引时非常容易踩坑比如倒序遍历数组时range(-1, -len(arr)-1, -1)这种写法一旦搞混取整方向就会出bug。数字类型还有一个很容易忽略的细节整数在Python里可以无限大只要内存放得下。我当时测试了一下2 ** 1000结果直接输出一个300多位的大整数这在C语言里早就溢出了。Python自动处理大整数溢出这件事确实省心但也会让初学者低估数据类型本身的边界问题等以后玩底层库比如numpy时才真正体会到类型转换的痛。符号、*这类复合赋值我也专门练了练它跟a a 1完全等价只是写法更简洁。不过有一点要注意对于不可变类型比如整数、字符串实际上是创建新对象再重新绑定而对于可变类型比如列表它可能是在原地修改。理解了这一层后面学函数传参、默认参数才不会莫名其妙出错。1.2 字符串不可变背后的含义字符串这块内容量比我想象中大得多。先记住一个结论字符串是不可变对象。什么叫不可变就是一旦创建就不能修改里面的某个字符。比如s hello s[0] H # 报错str object does not support item assignment我第一次看到这个报错时挺蒙的不是经常看到别人给字符串重新赋值吗后来才理解重新赋值是让变量指向一个新字符串而不是改动原字符串本身。就好比你换了个新手机但旧手机本身没被改造。这个特性对安全性和多线程很重要——多个地方同时引用同一个字符串时谁也不担心它被改掉。字符串的切片操作真是学Python以来觉得最爽的语法s python学习笔记 print(s[0]) # p print(s[-1]) # 记 print(s[0:6]) # python print(s[::-1]) # 记笔习学nohtyp[::-1]直接反转字符串一行代码搞定我一开始看到这种写法根本反应不过来后来把原理搞清楚就顺手了[start:stop:step]step为-1就是倒着走。这个语法很值得多写几遍因为列表、元组、字典这些容器类型全都遵循同一套索引规则学会了字符串切片就等于学会了所有序列类型的切片。字符串拼接有三个办法、join()、f-string。我用多了之后强烈推荐f-string格式化字符串。Python 3.6以后支持写法就是name 张三 score 92.5 print(f{name}本次得分{score:.1f}分)直接在字符串里嵌变量后面还能加格式控制符比如.1f表示保留一位小数。对比一下传统方式print(name 本次得分 str(score) 分) # 每个地方都要手动转换类型 print({}本次得分{:.1f}分.format(name, score)) # format也挺好但写起来略烦f-string不仅省事可读性还高了一大截。用了几次之后就回不去了强烈的建议是新代码一律用f-string别用拼接也别用format除非要动态构造格式化模板。1.3 布尔值与逻辑运算的直觉陷阱布尔值只有True和False两个值表面上简单但真正容易栽跟头的地方是哪些东西会被当成False以及and/or的返回值。Python里有一个概念叫真值测试在条件判断语境下以下值被视为FalseFalse本身数字0和0.0空字符串空列表[]、空元组()、空字典{}、空集合set()None其他一切值包括负数、0这个字符串都被视为True。这带来一个很常见的用处判断列表是否为空可以不用len(arr) 0直接写if not arr:简洁且符合直觉。但真正奇怪的是and和or的返回值。它们不只是返回True/False而是返回参与运算的某个值本身print(0 and hello) # 0 print(1 and hello) # hello print(0 or hello) # hello print( or 默认值) # 默认值原因是Python做了短路求值A and B如果A为假整个结果就是A不用再算B如果A为真结果取决于B。同理A or BA为真就直接返回AA为假才返回B。理解这一点之后很多为什么结果不是True/False的困惑都会解开。于是可以利用这个特性写很简洁的逻辑name input(请输入名字: ).strip() name name or 匿名用户 # 如果输入为空则使用默认值当然如果追求代码可读性这种写法可以适度使用毕竟不是所有人都知道短路求值的细节。我自己在项目里遇到这种逻辑更倾向于显式写下if not name: name 匿名用户团队协作时这种写法更安全。但个人脚本里用or设默认值确实省几行代码。2. 容器类型列表、元组、字典与集合的选型逻辑2.1 列表和元组一个可变、一个不可变列表是Python里用得最频繁的数据结构它就像一块可以随时增删改的白板。常用操作我总结了一下arr [1, 2, 3] arr.append(4) # 末尾加元素变成 [1, 2, 3, 4] arr.insert(0, 0) # 下标0位置插入变成 [0, 1, 2, 3, 4] arr.pop() # 删除并返回末尾元素arr变成 [0, 1, 2, 3] arr.remove(1) # 删除第一个值为1的元素 arr.sort() # 原地排序 arr[::-1] # 反转返回新列表元组tuple则恰恰相反它是不可变的point (3, 5) point[0] 10 # 报错你可能要问那为什么要用元组而不全部用列表最大的理由是语义约束。你希望某些数据创建后就不能被改动用元组等于告诉读代码的人这个数据是不可变的放心用。比如地理坐标、函数返回的多个结果用元组天然合适。第二个原因是性能元组比列表占用内存更小、创建更快面对大量数据时优势明显。第三个原因藏在字典的键里——列表不能作为字典的键因为可变对象有哈希失效风险元组可以。我在实际练习时感受最深的是解包unpackinga, b (10, 20) x, y 1, 2 # 不用括号也能解包 lst [1, 2] c, d lst # 列表也能解包这个特性在交换两个变量时特别好用。以前别的语言交换变量要引入第三个临时变量Python直接一行a, b b, a看到这种感觉特别爽。元组的不可变性不只是保护数据更重要的是让代码行为可预测尤其在多线程环境中不可变对象几乎没有并发风险。2.2 字典用名字找值字典dict是Python里最接近人脑思维的数据结构。在别的语言里叫map或哈希表核心就是键值对。生活中最典型的例子是通讯录人名是键Key电话号码是值Value。基本用法user { name: A同学, age: 18, city: 某城市 } user[age] 19 # 修改值 user[score] 88 # 新增键值对 print(user.get(email)) # 不存在时返回None不会报错 print(user.get(email, 未填写)) # 不存在时返回默认值需要注意的坑是直接访问不存在的键user[xxx]会抛出KeyError程序直接崩溃而get()方法返回None或自定义默认值不会中断流程。这个差异在写交互程序时非常关键。我一开始习惯直接下标访问后来被KeyError搞烦了就改成统一用get()了写代码的心情立刻舒畅不少。还有setdefault()方法也很好用——在键不存在时设置默认值存在则保持原值不动counts {} counts.setdefault(apple, 0) counts[apple] 1遍历字典有几种姿势for key in user: # 只取键 for key, value in user.items(): # 同时取键和值items()返回键值对列表 for value in user.values(): # 只取值Python 3.7之后字典会保持插入顺序这个特性让字典也可以当作有序结构用。但严格说字典的核心优势还是查找速度快——不管存100个还是10万个键值对查找时间基本不变哈希表的功劳。2.3 集合去重与关系运算集合set的底层也是哈希表但它只存key不存value所以有两个天然特性元素不重复查找极快。去重是集合最经典的场景scores [88, 90, 88, 75, 90, 100] unique_scores list(set(scores)) print(unique_scores) # [88, 90, 75, 100]一行代码搞定去重简单粗暴。当然如果对顺序有要求去重后列表顺序会打乱这时可以改用dict.fromkeys(scores)或写循环保持原顺序。集合的关系运算也很有用a {1, 2, 3, 4} b {3, 4, 5, 6} print(a b) # 交集 {3, 4} print(a | b) # 并集 {1, 2, 3, 4, 5, 6} print(a - b) # 差集 {1, 2} print(a ^ b) # 对称差 {1, 2, 5, 6}我在处理标签数据的练习题时用了集合并集合并了两个分类的所有标签代码更直观。比如判断一个集合是否是另一个集合的子集用a.issubset(b)或者a b在筛选数据时非常方便。选择容器类型的核心原则我总结成一句话需要顺序和下标用列表需要不可变保护和性能用元组需要键值对应快速查找用字典需要去重或集合运算用集合。四种容器各司其职脱离场景谈优劣没有意义。3. 控制流条件判断与循环的节奏感3.1 if/elif/else条件判断的优先级博弈条件判断是让程序活起来的第一步。Python的语法里没有switch语句多重判断用if/elif/else但写法上有一个非常关键的细节——条件的顺序。我在一道练习里犯过错判断学生成绩等级时我把所有条件都写在if里了排得又乱结果分数高的反而输出低等级。后来改成从高到低排列才正常score 85 if score 90: grade A elif score 80: grade B elif score 70: grade C elif score 60: grade D else: grade F为什么必须从高往低写因为Python按顺序执行条件一旦命中某个elif就跳过后面的所有判断。如果先写score 60那85分直接命中D永远到不了更高等级。条件的顺序本身就是逻辑的一部分排列不当是新手最常见的逻辑bug来源。这个细节在查资料时又发现了条件表达式的另一个常见坑if score 60 and score 80:这种写法自然没问题但初学者容易写出60 score 80其实Python支持链式比较简化了一些不必写and。三元表达式x if cond else y也值得掌握但不要嵌套太深否则可读性很差宁可拆成普通if。3.2 for循环与range遍历的两种思维for循环是Python里使用率最高的控制流结构。它的核心逻辑是遍历一个可迭代对象跟C语言里那种计数器从0数到N非常不一样。最常见的是配合range()for i in range(1, 11): print(i) # 输出1到10 for i in range(0, 10, 2): print(i) # 0, 2, 4, 6, 8步长为2 for i in range(10, 0, -1): print(i) # 10到1倒序range(start, stop, step)的三个参数分别是起始值含、结束值不含、步长。**stop不包含**这一点必须刻在脑子里我第一次想打印1到10时写的是range(1, 10)结果少了个10排查了半天还以为是代码有bug。除了遍历数字更常见的是直接遍历列表或字符串fruits [苹果, 香蕉, 橙子] for fruit in fruits: print(fruit)需要下标时优先用enumerate()它同时返回位置下标和元素值for index, fruit in enumerate(fruits): print(f第{index 1}个是{fruit})实际做练习题时我发现一个好用的技巧列表推导式list comprehension配合for循环能把原本5行的代码压缩成1行squares [x ** 2 for x in range(1, 11)] # 等价于 # squares [] # for x in range(1, 11): # squares.append(x ** 2)推导式是Python的标志性语法刚学可能不习惯但一旦用顺手写起来特别舒服性能还比循环加append快。后面学了好几个用推导式解决的问题以后越来越体会到这个特性的设计哲学表达意图而非描述步骤。3.3 while循环与break/continue什么时候该用循环while循环和for循环的区别一句话就能说清for适合知道要循环多少次的场景while适合不确定多少次、靠条件结束的场景。count 0 while count 5: print(count) count 1写while时最怕的就是死循环——条件永远为真程序跑不停。我第一天写while就遇到过一次循环体里忘了写count 1条件永远为真直接在终端里刷屏只能按CtrlC强制中断。打那以后我每次写while都会先检查循环体内有没有能让条件变假的语句。break和continue是循环的两个控制阀门for i in range(1, 20): if i 10: break # 直接结束整个循环 if i % 2 0: continue # 跳过本次循环的剩余部分进入下一次 print(i)实际场景里break特别适合做查找第一个满足条件的元素找到了就停下避免多余的遍历。continue则用来跳过不需要处理的数据项。while经常和break搭配实现一个很实用的模式用户输入循环。比如写一个猜数字小游戏secret 7 while True: guess int(input(猜一个数字: )) if guess secret: print(猜对了) break elif guess secret: print(小了继续猜) else: print(大了继续猜)while True配合内部的break等于一个什么时候退出由流程决定的循环比用变量控制条件更直观。但要注意这种写法必须保证循环内一定有break路径否则就是个死循环。4. 函数让代码从写一遍变成用很多遍4.1 定义函数与返回值函数的作用一句话说就是把代码组织起来复用。第一次自己写了一个小函数并连续调用三次时切实感受到写一次用多次的价值编程思维算是第一次建立起来。函数的基本结构很清爽def add(a, b): 返回两个数的和 return a b result add(3, 5) print(result) # 8def是关键字add是函数名括号里是参数return返回结果。文档字符串第一行的...用来写函数的说明我在练习时一开始总跳过不写后来发现写不写区别其实很大——隔几天再看旧代码瞬间明白每个函数干什么的感觉特别好。关于return有个微妙但重要的点函数没有代码直接return一个值时它会自动返回None。比如def greet(name): print(f你好{name}) result greet(张三) print(result) # Nonegreet函数只是打印没有返回值所以result是None。这种隐式None行为容易让人困惑尤其是你期望函数返回点什么东西的时候。判断一个函数是做事情还是算结果对理解整个程序的运行逻辑非常有帮助。4.2 参数传递的灵活玩法Python函数的参数系统非常灵活这也是它让新手少犯难的设计之一。主要有四种def show(a, b10, *args, **kwargs): print(a, b) print(args) # 元组存多余的位置参数 print(kwargs) # 字典存多余的关键字参数位置参数show(1, 2)a1, b2默认参数show(1)a1, b10可变位置参数show(1, 2, 3, 4)args(3, 4)可变关键字参数show(1, 2, name张三, age18)kwargs{name: 张三, age: 18}*args和**kwargs看起来高深实际用途非常实在。比如你写一个函数想接收任意数量的数字求和用*args就行def total(*nums): s 0 for n in nums: s n return s print(total(1, 2, 3, 4, 5)) # 15**kwargs则很适合处理字典形式的配置项。比如一个函数需要接收不确定的配置字段时def create_something(**config): print(f创建对象配置项有{len(config)}个) create_something(name测试, size100, colorred)默认值参数有个经典的坑是可变默认值陷阱def add_item(item, lst[]): lst.append(item) return lst print(add_item(a)) # [a] print(add_item(b)) # [a, b]第二次调用没用新的空列表原因是默认列表在函数定义时只创建一次每次调用如果没传lst用的都是同一个列表对象。解决方法是默认值设为None内部再新建列表def add_item(item, lstNone): if lst is None: lst [] lst.append(item) return lst这个坑我踩得印象深刻。调了两次函数发现第二次返回的列表里居然带着第一次的元素还以为自己哪里写错了。查了半天才明白是默认参数共享导致的。记住一条默认参数千万不要用可变对象一律用None再加判断。4.3 作用域函数内部与外部之间作用域指的是变量在哪些地方可以被访问。Python的规则用LEGB原则概括LLocal函数内部定义的变量EEnclosing嵌套函数中外部函数的变量GGlobal模块级别的全局变量BBuilt-inPython内置的名字比如len、print举一个直观的例子x 10 # 全局变量 def func(): x 5 # 局部变量跟全局的x互不相干 print(函数内部:, x) func() print(函数外部:, x) # 仍然是10函数内部的x 5是重新创建了一个局部变量不会改变全局的x。这就是我在第一周遇到的一个很意外的现象——在函数里改了一个变量出了函数一看根本没变。如果想在函数内部修改全局变量需要声明global但除非特殊情况我基本不用这个关键字。函数设计得越独立越容易测试和理解。如果你发现函数里要频繁操作全局变量更合适的做法是把要改的值作为参数传进去把结果通过return传出来def increment(num): return num 1 count 0 count increment(count) # 推荐这种写法这个模式看起来多写了一行代码但函数没有对外部环境做任何修改行为完全可预测这就是函数式思维的一个雏形。同时给可读性带来的好处是一个函数的输入输出看起来清清楚楚测试起来也容易。嵌套函数那种nonlocal关键字的用法我先放一边了目前练习里用不上知道有这个概念就行。等以后学闭包和装饰器时再深挖不迟。5. 学习过程中的踩坑记录与实用心得5.1 我踩过的几个具体坑这周踩坑不少挑几个印象深刻的记录下来第一个坑是字典键不存在。那时候写了个统计字符出现次数的程序text hello counts {} for ch in text: counts[ch] 1 # KeyError: h直接报错因为第一次遇到键h时字典里根本没有这个键。正确写法是for ch in text: counts[ch] counts.get(ch, 0) 1或者用defaultdict但当时还没学collections模块用get()已经能解决。第二个坑是忘记转换数据类型。我写了个加法计算器输入两个数字后一运行输出的居然是两个字符串拼在一起。原因很简单input()返回的是字符串直接就是字符串拼接。需要转成int再相加a int(input(第一个数: )) b int(input(第二个数: )) print(a b)这个错误让我学到一个习惯每次接收input()的结果先问自己它现在是字符串我需要它是什么类型。第三个坑是函数内部变量访问冲突。我写了一个函数想在函数内部读全局变量的值又想改全局变量的值结果一会儿报错一会儿不报。后来才彻底理解只要函数内出现了x ...这样的赋值语句Python就把x当成局部变量前面的print(x)也会报局部变量x在赋值前被引用。如果确实要改全局变量就得用global x声明。5.2 第2周小结学到什么程度算学会学完数据类型和控制流之后我对学会有了新的定义不是看懂了书上的例子而是能独立写出完整的小程序。所以我给自己设定了一道综合题大概长这样# 简易成绩统计系统 scores [] while True: user_input input(输入成绩输入q退出: ) if user_input q: break try: score float(user_input) scores.append(score) except ValueError: print(输入无效请重新输入) if scores: average sum(scores) / len(scores) print(f共{len(scores)}条成绩平均分{average:.2f}分) above [s for s in scores if s 60] print(f及格人数{len(above)}人及格率{len(above) / len(scores):.1%}) else: print(没有有效成绩)这段代码几乎用尽了本周学的内容while循环、break、try/except、input、float转换、if判断、列表、append、列表推导式、f-string、百分比格式化。如果能不看资料写出来并运行成功我觉得这周就算过关了。还有一点想说的是这个阶段看文档和查资料一定会很频繁这完全正常。我自己遇到忘记某个方法时就直接打开交互式解释器测试help()和dir()这两个内置函数我一天能用到好几次。尤其是dir()输入dir(list)就能列出列表的所有方法名加上help(list.append)看具体说明相当于随身带了一个API手册。逐步思考逐步验证不懂就试多写多跑学习过程的思路应该就是这样。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询