资讯动态

Python基础语法避坑指南:变量、缩进与字符串详解

发布时间:2026/10/24 19:15:18 来源:尧图企业网站定制
简介这份68页的Python基础语法合集专为初学Python的入门者与希望快速回顾语法要点的开发者设计从解释型动态语言的特点出发系统梳理变量与多变量赋值、Numbers/Strings/Lists/Tuples/Dictionaries等核心数据类型、运算符、流程控制、函数定义、模块导入等知识并结合标识符命名规则、严格缩进、多行语句写法、换行输出等细节帮助读者规避常见误用、夯实基础。资源为单一PDF文档压缩包1.42MB便于离线阅读、打印或作为日常速查手册。目前已有2048人学习内容涵盖内置类型转换、数学函数与随机数函数、if/elif/else条件分支、for/while循环、try-except异常处理等高频率考点68页紧凑编排每节配有可运行的示例代码与要点说明适合自学、备课或面试前快速过一遍语法。1. Python 基础语法合集为什么我建议初学者先啃这份 PDF带过两个转行过来的新人之后我越来越倾向让初学者先啃语法手册而不是一上来就追框架。这份 Python 基础语法合集就是把变量、数据类型、字符串、列表、元组这些最容易混的基础点按顺序铺开每个点都配了短代码示例。它不能让你写出多漂亮的工程代码但能让你在报错的时候知道错在哪而不是对着黑匣子瞎猜。适合两类人零基础想系统过一遍语法的以及写过脚本但一直靠复制粘贴、对缩进和类型边界说不清楚的人。下面我按自己的复习路线把这份材料拆成几条实战线索从地基语法一直走到自测闭环。2. 把语法地基先立住标识符、缩进、保留字与多行写法的四个边界2.1 标识符规则里最容易被忽略的三个边界Python 的标识符由字母、数字、下划线组成不能以数字开头而且大小写敏感。这个规则看起来简单但我在实际代码里见过三种翻车方式。第一种是把下划线开头的变量当作普通变量随便导出结果在别的模块里用from xxx import *导不进来。单下划线开头的_foo表示“我不希望你直接访问”它不是一个强约束但属于约定俗成的边界。双下划线开头的__foo在类里会被重新命名为_ClassName__foo这是为了避免继承时名字冲突所以不要以为它只是“私有”两个字能概括的。双下划线开头和结尾的__foo__是 Python 专门留给特殊方法的名字比如__init__是构造函数__len__控制len()行为普通业务代码里最好别自己造这种名字。大小写敏感这一点初学者最容易在复制代码时吃亏。UserName和username是两个完全不同的变量我见过有新人把函数参数写成userName内部却用username访问结果抛NameError他还在怀疑是不是环境装坏了。看这份语法合集时我建议你每看完一节就在交互式环境里敲一遍不要只看不写。标识符这一节真正要记的是边界不是“由字母数字下划线组成”这句话。# 合法的标识符 user_name u1 # 正常变量 _user_age 28 # 单下划线开头模块内私有from xxx import * 不会带上它 __salary 12000 # 双下划线开头类里会做名称改写避免子类冲突 __version__ 1.0 # 双下划线首尾特殊方法/属性专用业务代码别模仿 # 非法或不建议的写法 # 1name u2 # 数字开头SyntaxError # class python # 保留字SyntaxError这段代码里_user_age和__salary是两种不同级别的“私有”写法。单下划线只影响from module import *的默认行为你仍然可以主动import module后访问module._user_age。双下划线则会在类定义时被改名直接访问obj.__salary会报AttributeError但通过obj._ClassName__salary还是能摸到所以它防的是误用不是恶意攻击。__version__这种名字是协议的一部分比如__init__、__str__看到这类标识符第一反应应该去查对应的特殊方法语义而不是拿来起业务变量名。2.2 缩进才是 Python 的代码块边界从一次缩进错误说起这份材料里有一句很容易被划过去的话“Python 的缩进要求非常严格必须严格对齐。”很多从 C 或 Java 转过来的人觉得这是小事直到自己写的函数报出IndentationError: unexpected indent才意识到问题。Python 不用{}括代码块缩进就是语法本身。同一个代码块里的每一行缩进必须完全一致而且在 IDE 里看起来对齐了实际却可能藏着一个 Tab 和四个空格混用的问题。我一般会建议把编辑器的缩进统一成四个空格并且打开“显示空白字符”功能。原因很简单Tab 在同一个编辑器里可能显示为 4 个空格在另一个编辑器里显示为 8 个别人一打开你的文件整个缩进层级就乱了。Python 3 还专门把混用 Tab 和空格的情况提示为TabError: inconsistent use of tabs and spaces in indentation这是好事情它把问题提前暴露了。遇到这类报错不要靠肉眼一行行找直接选中代码看编辑器状态栏或者用python -m tabnanny script.py这样的工具列出可疑行。def judge_score(score): if score 60: print(pass) # 属于 if 块 print(with comment) # 和上一行同层级也是 if 块 else: print(fail) print(done) # 这个属于函数体不属于 if/else # 错误示范同一代码块内缩进宽度不一致 # if score 60: # print(pass) # print(extra) # 多缩进了一格IndentationError上面这个例子说明了缩进级别的层级关系。if下面的print行和if之间缩进 4 个空格表示它是条件成立时要执行的语句最后一个print(done)缩进 4 个空格但和if、else对齐说明它属于函数体无论条件真假都会执行。如果你发现某个 print 在条件判断之后仍然执行先检查它的缩进层级是不是和if平级了。这是排查逻辑问题最快的手段。2.3 多行语句与多行字符串用斜杠还是括号附对照除了缩进这份材料还专门讲了多行语句的写法。用反斜杠\可以把一行的语句拆成多行这是 C 系语言的习惯。但 Python 里其实有更好的选择只要写在小括号、中括号、花括号内部就可以直接换行不需要反斜杠。我自己的习惯是只要是表达式拼接一律用小括号包起来换行避免行尾遗留反斜杠。反斜杠一旦后面不小心跟了个空格就会变成语法错误而且这个空格肉眼几乎看不见属于典型的“看着没问题但一跑就炸”。total item_one \ item_two \ item_three # 用反斜杠行尾不能有任何空白 total (item_one item_two item_three) # 用括号换行自由推荐写法 # 同一行多条语句用分号 a 1; b 2; c 3 # 三引号多行字符串 text 第一行 第二行 第三行 print(text)注意三引号的作用不只是多行字符串它还能当多行注释用。但严格来说三引号包起来的内容是一个字符串对象如果不把它赋给变量也不参与表达式它就是一个被丢弃的表达式解释器不会报错所以很多人把它当注释。我建议正式代码里不要依赖这种“注释”因为它在某些静态检查工具里会被认为是无用的字符串表达式。多行语句这条规则配合缩进构成了 Python 代码最基础的可读性来源。写法优点风险反斜杠\直观单行过长时简单行尾不能有空格容易踩坑括号内换行不需要额外符号IDE 容易自动整理初学者容易忘记闭合括号三引号适合大段文本、文档字符串不是一个真正的注释别滥用这张表不是让你背而是给你一个选型依据写长条件、长拼接时优先用括号。if (条件1 and 条件2)这种写法在 Python 里也完全合法而且能避免and后面的行被误以为是新语句。另一条材料里提到的小细节是分号a 1; b 2; c 3在交互式环境里可以省行数但正式脚本里没人这么写主要是影响可读性而且出现异常时不好定位是哪一句。你只要知道分号能同行分隔语句就够了别把它当风格。这一章看下来标识符、缩进、多行语句其实都不是“功能”但它们决定了你后面写出来的代码能不能被 Python 正确解析。我见过太多人把IndentationError看成天书实际就是把缩进统一、行尾空格清掉问题就少了一半。3. 变量与数字类型类型转换、数学函数与随机数函数的落地用法3.1 五个标准数据类型与不可变对象的赋值陷阱材料把标准数据类型分成 Numbers、String、List、Tuple、Dictionary 五大类。这个分类在 Python 3 里依然成立只是 Numbers 内部的 long 类型已经合并进 int。我建议你记的不是分类本身而是“哪些是不可变类型”。数字、字符串、元组不可变列表和字典可变。这里有个很容易翻车的赋值陷阱b a对于不可变对象相当于让 b 指向 a 当前引用的对象之后给 a 重新赋值不会影响 b但对于可变对象b a只是复制了引用修改 b 的内容a 也会跟着变。# 不可变对象数字 a 100 b a a 200 print(b) # 100b 还指向原来的整数对象 # 可变对象列表 x [1, 2, 3] y x y.append(4) print(x) # [1, 2, 3, 4]x 和 y 指向同一个列表 # 想要独立副本 z x[:] z.append(5) print(x) # [1, 2, 3, 4] print(z) # [1, 2, 3, 4, 5]从这个例子里能读出一个关键结论判断“改了一个变量会不会影响另一个”不是看变量名而是看对象是否可变。数字和字符串在重新赋值时会创建新对象并让变量指向新对象所以原来的变量不会变。列表这类可变对象直接在原对象上做修改所以所有引用它的变量都会感知到变化。材料里提到的del语句也有同样的逻辑del a删除的是“a 这个引用”不是立刻销毁对象如果还有别的变量引用同一个对象对象仍然存活。3.2 类型转换函数清单与选择依据类型转换这节列出了十多个函数但真正每天都会用到的也就是int()、float()、str()、list()、tuple()这几个。int(x, base)的第二个参数在解析字符串时非常有用比如用户输入ff你用int(ff, 16)就能拿到 255。repr()和str()的区别也值得记一下str()返回面向用户的字符串repr()返回面向解释器的表示很多对象的repr()是可以通过eval()还原的。# 字符串转数字 num int(42) print(num 1) # 43 # 带基数解析十六进制字符串 hex_val int(ff, 16) print(hex_val) # 255 # 数字列表与元组互转 lst [1, 2, 3] tup tuple(lst) lst2 list(tup) print(tup, lst2) # eval 的坑不要对不可信字符串用 expr 1 2 print(eval(expr)) # 3这里要说一个边界eval()虽然列在类型转换函数里但它的能力远不止类型转换它会执行任意 Python 表达式。如果这个表达式来自用户输入等于把解释器权限交出去了。我一般只在调试脚本里用或者处理自己生成的配置文件绝不让它碰外部输入。int()转换时如果遇到int(4.5)会抛ValueError正确做法是先float()再int()或者用math.floor()、math.ceil()控制取整方向。3.3 数学函数与随机数函数的常用组合数学函数这节最适合用“查表法”学。abs()取绝对值round()四舍五入pow()和**等价sqrt()开平方ceil()向上取整floor()向下取整。这里最容易踩坑的是round()的银行家舍入比如round(2.675, 2)在大多数版本里会得到2.67而不是2.68因为它处理的是浮点数的二进制表示不是十进制。如果对精度有要求用Decimal别用round()做财务计算。import math, random # 数学函数组合 scores [77.6, 88.3, 92.1] average sum(scores) / len(scores) print(math.floor(average)) # 向下取整 print(math.ceil(average)) # 向上取整 print(round(average, 1)) # 保留一位小数 # 随机数模拟掷骰子 dice random.randint(1, 6) # 常用但材料里未列出的函数等价于 randrange(1, 7) print(dice) # 从列表中随机选一个 player random.choice([u1, u2, u3]) print(player) # 打乱列表 cards [1, 2, 3, 4, 5] random.shuffle(cards) print(cards)随机数函数这里材料列了choice、randrange、random、seed、shuffle、uniform。我建议再补一个randint(a, b)它等价于randrange(a, b1)使用频率很高。seed()的作用是固定随机序列测试环境里常用你给seed(10)后续随机结果在每次运行里都一样方便复现。但注意seed()只影响当前随机数生成器的状态不是全局魔法不同 Python 版本或不同进程的生成器算法可能不同线上环境别指望它跨平台完全一致。材料还列了acos、asin、cos这些三角函数以及pi、e两个常量。实际写代码时我很少直接用math.degrees()和math.radians()之外的三角函数但如果你要做坐标计算、图像旋转至少要知道角度和弧度不能混用。math.sin(math.radians(30))才是按角度传参的标准姿势直接math.sin(30)会把 30 当成弧度结果差得很远。数学常量pi和e也是同样的道理用math.pi而不是自己定义3.14能省掉很多精度上的玄学问题。4. 字符串操作截取、转义、格式化与内建方法的排错思路4.1 截取索引的方向与边界从左从右怎么取字符串是 Python 里最“绕”的类型之一因为它的索引和切片规则同时涉及正反两个方向。从左往右索引从 0 开始最大到长度减 1从右往左用负数-1是最后一个字符。切片s[start:end]是左闭右开的也就是说取到的字符包括 start但不包括 end。这个左闭右开规则是所有切片操作的核心也是新手最容易看晕的地方。s hello print(s[0]) # h print(s[-1]) # o print(s[1:4]) # ell索引 1 到 3不包括 4 print(s[:3]) # hel省略 start 从头开始 print(s[3:]) # lo省略 end 到最后 print(s[-3:-1]) # ll从倒数第 3 个到倒数第 2 个排错时我习惯先写一个测试字符串把每个字符的索引标出来再验证切片结果。比如hello索引 0 到 4负数版本就是 -5 到 -1。s[1:4]之所以是ell就是因为 start1 包含 eend4 不包含 o。如果你想要整个字符串写s[:]就行它返回的是原字符串的副本。对字符串来说这个操作没什么必要但用在列表上就能得到新的列表副本和上一章的切片复制是同一个机制。4.2 转义字符和三引号什么时候不用再背转义表材料里给了一张很长的转义字符表\n、\t、\\、\这些看一眼就行不建议死背。真正要理解的是“反斜杠是把特殊字符翻译成控制字符”。比如\n不是两个字符而是一个换行符。如果你需要输出路径C:\new直接写C:\new会把\n当成换行这时候有两个办法用双反斜杠C:\\new或者用原始字符串rC:\new。# 原始字符串不解析转义 print(r\n\t) # 输出 \n\t 这两个字符 print(\\n\\t) # 同样输出 \n\t # 三引号大段文本不用写一堆 \n text 第一行 第二行 第三行 print(text)使用原始字符串时有个边界要记住它不能以单个反斜杠结尾比如rabc\会语法错误因为最后的反斜杠仍然会转义引号。这种场景我一般改用普通字符串加双反斜杠。三引号最大的价值是处理带格式的文本比如 HTML 模板、SQL 语句、多行日志直接换行写不用手动拼\n可读性会好很多。4.3 格式化输出的演进从 % 到 format这份材料里主推的是%格式化比如My name is %s and weight is %d kg! % (u1, 21)。这个写法在 Python 3 里仍然合法但已经不算主流。format()方法提供了更灵活的字段定位而 f-string 是 Python 3.6 之后最直观的写法。我的建议是学语法时把%看懂因为你要读老代码写新代码时优先 f-string。name u1 weight 21 # % 格式化材料主推 print(My name is %s and weight is %d kg! % (name, weight)) # format 方法 print(My name is {} and weight is {} kg!.format(name, weight)) # f-string最推荐 print(fMy name is {name} and weight is {weight} kg!)这里有个排错点%s接受任意类型传入会先转成字符串%d必须接收整数或能转成整数的值。如果你写%d % 21Python 3 会抛TypeError而不是自动转换。老代码里这种问题很常见解决思路是显式int()转换或者直接改用 f-string让变量保持原类型输出。4.4 字符串内建方法查询类与修改类分开记字符串方法有几十个按作用分成两类记会轻松很多。查询类包括find()、index()、count()、startswith()、endswith()修改类包括replace()、strip()、lower()、upper()、split()、join()。这里最容易搞混的是find()和index()find()找不到子串时返回 -1index()找不到时抛ValueError。所以如果你只是判断有没有用in或find()如果你认为一定有用index()让它尽早暴露问题。text hello python world # 查询 print(text.find(python)) # 6 print(text.startswith(hello)) # True print(text.count(o)) # 2 # 修改 print(text.replace(world, code)) print(text.upper()) print(text.split()) # [hello, python, world] print(-.join([a, b, c])) # a-b-c print( padded .strip()) # paddedsplit()和join()是逆操作一个是把字符串按分隔符切成列表一个是把列表用分隔符拼回字符串。我处理表格数据、命令行参数时经常用这两个方法。另外strip()默认去掉两侧空白字符不只是空格还包括\t、\n这个容易被人忽略。如果你只想去掉某一侧用lstrip()和rstrip()。5. 避坑这份语法合集里最容易翻车的五个点与排查步骤读这份材料时很多例子在命令行里能跑通但一挪到实际项目就出问题。下面这五个点是我在带人时反复遇到的每一个都对应一份真实报错记录按现象、原因、解决三步拆开。5.1 缩进报错看着对齐了一跑就炸现象代码在编辑器里显示得很整齐但一运行就报IndentationError: unexpected indent或TabError报错行指向某个看似无辜的print。你反复调整空格数量问题依然随机出现在不同行。原因材料强调“缩进必须严格对齐”但没强调 Tab 和空格的区别。很多编辑器默认把 Tab 显示成 4 个空格的宽度所以肉眼看起来对齐了实际代码里既有 Tab 又有空格。Python 解释器按字符判断缩进层级同一个代码块里混用两种字符就会报错而且报错位置往往不是真正的源头而是解释器第一次发现缩进冲突的那一行。解决把所有缩进统一成 4 个空格。在编辑器设置里关闭 Tab 缩进或者打开“显示空白字符”。已经混用的文件可以用python -m tabnanny script.py找出具体位置。如果文件是别人给的全选代码后用编辑器的“将 Tab 转换为空格”批量处理然后再运行。之后我写 Python 之前都会先确认编辑器右下角的缩进提示。5.2 单元素元组忘了加逗号类型不是元组现象写了t (5)然后用type(t)检查发现不是tuple而是int。用t (hello)拿到的是字符串而不是元组。更隐蔽的是t (a, )这种写法被后来的维护者“好心”删掉逗号后程序不报错但行为变了。原因括号在 Python 里有两种作用一种是改变运算优先级一种是表示元组。当括号里只有一个元素且没有逗号时解释器把它当作分组括号不会创建元组。材料里虽然写了“创建只有一个元素的元组必须加逗号”但很多人只读不验或者只在创建tuple()空元组时记得加括号碰到字面量又忘了。解决创建单元素元组时写成(5,)逗号不能省。检查时用type()而不是靠眼睛。如果心里没底可以用tuple([5])这种显式构造来避免括号语义歧义。我在代码评审时看到return (result,)这类写法都会顺手在旁边注释一句“这里的逗号是故意的”防止后面被删掉。5.3 格式化类型不匹配%d 收到字符串就翻车现象执行%d % 21报TypeError: %d format: a number is required, not str。在 Python 2 里这段代码可能能跑但在 Python 3 里直接失败。报错信息里的“a number is required”很容易让新手误以为变量值不是数字其实只是类型字符串。原因%d要求参数是整数而变量里存的是字符串。材料里的例子都是手动写好的类型实际业务中变量可能来自配置文件、命令行参数、用户输入全是字符串直接拼接就会炸。%s却能接受任意类型所以同一个格式化字符串里混用%s和%d时错误只在%d那一个位置暴露看起来像灵异事件。解决先int()转换再格式化或者改用 f-string。还要注意int()的边界int(4.5)会抛ValueError因为int()不接受带小数点的字符串要先转float()再转int()。排查时在格式化前打印type()能直接看到数据类型不用猜。5.4 Python 2 语法残留print 是语句long 是类型现象把材料里某些例子抄到 Python 3 里运行报SyntaxError: Missing parentheses in call to print或者看到long类型名称飘红。在交互式环境里输入print hello会直接语法错误而不是输出字符串。原因这份材料的不少例子带有早期 Python 2 的痕迹比如print x、数字后面的L后缀、cmp()函数。Python 3 中print是函数必须加括号long已经合并到intcmp()被移除替代方案是(a b) - (a b)。很多初学者以为是自己电脑环境坏了其实是语法版本问题。解决统一用 Python 3 语法。print(x)代替print x看到数字后面的L后缀直接删掉遇到cmp()逻辑按(a b) - (a b)重写。如果照着材料练习时频繁遇到这类错误先在文件头部写清楚用的 Python 版本再逐条检查。我用python --version确认环境后就把所有print语句全局替换了一遍。5.5 变量复制变成引用列表跟着一起变现象b a之后b.append(1)结果a也多了元素。很多人误以为 Python 的赋值都是拷贝于是出现“一个变量改动另一个莫名跟着变”的灵异事件。字典也有同样问题d2 d1后修改d2d1同步变。原因列表和字典是可变对象b a只是让b和a指向同一个对象。材料在数字类型部分讲了不可变对象但没特别强调列表的引用语义。实际上数字、字符串、元组赋值后互相独立列表、字典、集合赋值后共享同一个对象这是新手期最常遇到的隐性坑。解决需要独立副本时用a[:]、a.copy()或copy.deepcopy(a)。如果列表里还有嵌套列表浅拷贝只能复制外层内层仍然是引用这时要用copy.deepcopy()。排查时可以在赋值后打印a is b返回True就说明是同一对象改一个必然会变另一个。a [1, 2, 3] b a[:] # 浅拷贝 b.append(4) print(a) # [1, 2, 3] print(b) # [1, 2, 3, 4] import copy nested [[1], [2]] deep copy.deepcopy(nested) deep[0].append(99) print(nested) # [[1], [2]] print(deep) # [[1, 99], [2]]现在我遇到可变对象赋值第一反应是问自己“我要的是引用还是副本”。这个习惯能省掉一大半难以定位的“变量被悄悄改掉”类问题。6. 把这份语法合集变成自己的速查表用自测脚本验证掌握度6.1 把知识点变成断言读这份材料最大的陷阱是“眼睛会了手不会”。我给自己的方法是把每个知识点压缩成一个assert写进一个syntax_check.py每次读完就跑一遍。断言通过不是目的目的是让报错告诉你哪里理解偏了。下面是一个能跑通的最小骨架它覆盖了缩进、单元素元组、格式化、切片、列表复制五个关键点# syntax_check.py name python if name python: print(缩进正常) t (5,) assert type(t) is tuple # 单元素元组必须有逗号 score 88 assert f{score} 88 # f-string 输出字符串 word python assert word[1:4] yth # 切片左闭右开 a [1, 2] b a[:] b.append(3) assert a [1, 2] and b [1, 2, 3] # 切片复制得到独立列表 print(all checks passed)跑这个脚本时把报错当成线索而不是挫败。SyntaxError大多指向缩进、括号或引号问题回到第 2 章查AssertionError是知识理解有偏差比如切片边界、元组逗号、可变对象复制。我会建议你每读完一个章节就往上追加两条断言把材料里的示例改成“输入一个值断言输出是什么”而不是只在命令行里看打印。这样做有一个额外好处当 Python 版本升级或你换了环境脚本能帮你快速确认基础语法没有被破坏。从那以后我每次拿到新的语言手册都会先花半小时写一个自检脚本把所有容易混的边界变成断言跑通后才算真正读过。希望帮到你。本文还有配套的精品资源点击获取

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

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

免费获取报价 →
↑