自学Python这件事,最怕的不是看不懂,而是头两天就轻飘飘地滑过去。《自学Python100天》这个系列我按自己的学习节奏整理,D2这天的主题是“语言元素”,也就是变量、数据类型、运算符、表达式、输入输出这些最基础的零件。语言元素说通俗点,就是Python的“单词和语法”,后面写的任何程序,本质上都是把这些零件按规则拼起来。如果你正准备从零开始,或者已经看过D1但脑子里还是乱成一团,这篇笔记正好可以帮你把地基打稳。我不打算给你抄一堆规则,而是按我真实踩坑的顺序,把这天该掌握的东西摊开讲清楚。
1. 语言元素到底指什么——先理清学习地图
1.1 从搭积木看语言元素
任何一个程序,不管看起来多花里胡哨,最后做的事情永远只有三件:拿数据、算数据、给结果。D2要学的语言元素,就是围绕这三件事的最小工具集。变量帮你临时存放数据,数据类型决定数据长什么样,运算符负责加工,输入输出负责把数据送进程序、把结果推出来。
我习惯把写程序类比成做菜。D1你学会了开火和关火,知道用print()能端出一盘最简单的菜。D2开始认识食材:变量是装食材的碗,数据类型是区分蔬菜、肉类、调料的标签,运算符是刀法、火候。刀法不熟,食材切不对,后面学再多菜谱都是空中楼阁。
很多教程会把语言元素拆成一大堆术语,看得人脑壳疼。其实你只需要记住一句话:代码就是把“数据”和“对数据的操作”用“语法”串起来。D2真正要做的,就是把数据怎么存、操作有哪些、语法长什么样这三件事,用一整天的时间过一遍。
1.2 语言元素清单
D2涉及的核心零件,我把它列成一张清单,后面每个知识点都对应到清单上:
- 变量:给数据贴个名字,之后用名字操作数据。比如
age = 25。 - 常量:值始终不变的量。Python没有真正的常量,但约定俗成用全大写变量名表示“别改它”,比如
PI = 3.14159。 - 数据类型:区分整数、小数、字符串、布尔值等,决定数据能不能做某些运算。
- 运算符:负责计算和比较,比如
+、-、*、/、==、and。 - 表达式:变量、常量和运算符组合出来的“可计算式子”,比如
a + b * 2。 - 注释:写给人类看的说明,程序执行时会忽略。
这六项,就是D2的全部主线。你可能觉得少,但后面的列表、字典、函数、循环,全都是建立在这些零件之上的。我见过太多人第一天草草装完环境,第二天跳过这些细节直接去学列表推导式,结果输出报错时连TypeError和ValueError都分不清。语言元素不是“简单”,而是“基础”,基础不稳,后面全是补坑。
1.3 第二天到底要怎么学才不白费
我个人的建议是,这一天的学习不要以“看完”为目标,而是以“敲完”为准。打开Python交互式环境,或者新建一个d2_demo.py文件,看到示例就敲一遍,敲完了故意改几个地方让它报错,再试着修好。报错才是学习效率最高的时候。
具体玩法很简单:
- 先把下面每一小节的代码复制到文件里,运行一遍。
- 把自己代入进去,想一下“如果这里改成另一种写法会怎样”。
- 把遇到的所有报错截图或记录下来,自己总结原因。
我在这一天犯了至少七八个低级错误,但正因为每个错误都是在键盘上真实敲出来的,第二天再看数据类型和运算符的时候,脑子里的印象特别清晰。光看不敲,等于看菜谱没下厨,看完就饿。
2. 变量和类型:数据的基本容器
2.1 变量不是盒子,是标签
很多人一开始理解变量,脑子里会浮现数学课上的“未知数x”。但在Python里,变量更像是一个“名字贴”,它贴在某个对象上,让你以后能通过这个名字找到对应的数据。
age = 25 print(age) # 25 age = 26 print(age) # 26这两行代码做了什么?Python先创建了一个整数对象25,然后把名字age贴上去。第二行赋值时,又创建了整数对象26,把名字age从25上撕下来贴到26上。25那个对象如果没有其他引用,就会被Python的垃圾回收机制自动清理掉。这也是Python和C语言很大的一个区别:变量本身没有类型,类型属于它指向的“对象”,所以一个变量可以先后指向不同类型的数据。
变量命名的规范必须刻进DNA里:
- 只能由字母、数字、下划线组成,不能以数字开头,所以
3dogs直接报SyntaxError。 - 不能和Python关键字重名,比如
if、for、while、class这些都不能当变量名。 - 区分大小写,
age和Age是两个完全不同的变量。 - 尽量别用
print、input、str这些内置函数名当变量,否则后面调用函数时会得到一堆奇怪的报错。
命名风格上,Python社区推荐小写字母加下划线,比如user_name、total_score。短一点没关系,怕的是a1、b2这种,三天后你自己都看不懂。
2.2 常见的内置数据类型
D2阶段最常用的是下面这五种内置类型:
| 类型 | 中文名 | 例子 | 说明 |
|---|---|---|---|
int | 整数 | 3,-10,2024 | 任意大小的整数,注意没有长度限制 |
float | 浮点数 | 3.14,-0.5,1e3 | 带小数的数,底层按二进制存储 |
str | 字符串 | "hello",'自学' | 用单引号或双引号包裹的文本 |
bool | 布尔值 | True,False | 只有两个值,注意首字母大写 |
NoneType | 空值 | None | 表示“空”或“还没有值” |
怎么知道一个数据是什么类型?用type()函数:
age = 18 print(type(age)) # <class 'int'> price = 9.9 print(type(price)) # <class 'float'> name = "小明" print(type(name)) # <class 'str'> flag = True print(type(flag)) # <class 'bool'>这里有个很反直觉的点:True和False在参与算术运算时,分别会被当成1和0。所以True + 1的结果是2。这在某些情况下会带来隐蔽bug,比如统计有多少个True时没问题,但你手动做乘法时就会莫名其妙多出数据。我自己的原则是:布尔值只用于判断,不参与算术。
2.3 类型转换:让数据变得更顺手
类型转换是D2的重头戏,因为后面你会频繁遇到“数据是字符串,但你想拿它算数”的场景。转换函数很直白:
int(x):把x转成整数,比如int("3")得到3。float(x):把x转成浮点数,比如float("3.14")得到3.14。str(x):把x转成字符串,比如str(123)得到"123"。bool(x):把x转成布尔值,比如bool(0)得到False,bool("abc")得到True。
看起来简单,坑也不少。最典型的一个:
number = int("3.14")这段代码会直接报ValueError: invalid literal for int() with base 10: '3.14'。原因是int()只认“长得像整数”的字符串,不认小数文本。想把"3.14"变成整数,应该先转浮点数,再判断要不要取整:
number = int(float("3.14")) print(number) # 3另一个容易出现认知偏差的是bool()规则。空字符串""、数字0、0.0、None都会转成False,其他几乎都是True。所以bool("False")的结果是True,因为字符串里只要有字符,它就是“非空”。
我给初学者的一句建议:但凡从input()拿到的东西,一律先当作字符串看待,等你想清楚它下一步要参与什么运算,再决定是否转换。
3. 运算符与表达式:控制计算的规则
3.1 算术运算符和优先级
D2核心的算术运算符有七个:+-*///%**。其中+和*还能作用于字符串,分别表示拼接和重复,这个知道即可。
最容易混的是除号家族。Python3里,单斜杠/做除法,结果一定是浮点数,比如3 / 2等于1.5。双斜杠//做整除,结果向下取整,比如3 // 2等于1,但-3 // 2得到-2,因为它往更小的方向取整,这一点和数学里的向下取整一致,很多新手会在这里收获第一个惊喜。
取余数%也很常用,9 % 5等于4,10 % 5等于0。判断一个数是奇数还是偶数,就看x % 2是1还是0。乘方**用法是2 ** 3等于8。
优先级上,Python和数学课大体一致:括号最优先,然后是**,接着是*、/、//、%,最后是+、-。看个例子:
result = 2 + 3 * 4 ** 2 print(result) # 2 + 3 * 16 = 50实际操作里,我不建议依赖优先级记太多,复杂表达式直接加括号,既避免自己算错,也方便别人读代码:
result = 2 + (3 * (4 ** 2))3.2 比较运算符与逻辑运算符
比较运算符有六个:==(相等)、!=(不等)、>、<、>=、<=。它们的结果都是布尔值,要么True,要么False。
Python有个非常舒服的写法,其他语言里不太常见,就是链式比较:
score = 85 print(60 <= score <= 100) # True这比写score >= 60 and score <= 100要直观得多,强烈推荐。
逻辑运算符有三个:and、or、not。它们的优先级是not最高,and次之,or最低。但为了可读性,我建议任何组合都加括号,防止自己和别人看岔了。比如:
# 表示年龄在18到60之间,或者有特殊通行证 if (age >= 18 and age <= 60) or pass_card == True: print("allowed")再强调一下:a = b是赋值,a == b是判断相等。初学者最容易把判断里的==写成=,于是代码变成“把b的值塞给a”,结果自己被SyntaxError和诡异逻辑搞到怀疑人生。我D2这一天至少犯了三次这个错误。
3.3 赋值运算符与复合赋值
最基本的赋值是x = 1。Python还支持链式赋值和多重赋值:
# 链式赋值:两个变量都指向0 x = y = 0 # 多重赋值:左右数量一致 a, b = 1, 2多重赋值最妙的用途是交换两个变量。其他语言通常要写一个临时变量,Python里直接:
a, b = b, a这一行代码的执行顺序是:先把右边的(b, a)打包成一个元组,再按顺序解包给左边的a, b。不需要中间变量,干净利落。
复合赋值运算符,就是把算术运算和赋值合并起来:+=、-=、*=、/=、//=、%=、**=。例如:
n = 10 n += 5 # 等价 n = n + 5 print(n) # 15注意Python不支持n++或n--这种写法。第一天用的高频操作是count += 1,把这句话记住,后面循环里天天用。
3.4 表达式与语句的差别
表达式是有“值”的一段代码,比如2 + 3、x * 2、name == "小明"。语句是执行某个动作的代码,比如x = 5是赋值语句,print(x)是输出语句。
在Python交互式环境里,输入表达式会直接显示它的值:
>>> 2 + 3 5但在脚本文件里,表达式不会自己把结果显示出来,你必须写print(2 + 3)才能看到。很多新手在交互式里体验很好,一到写文件就以为哪里没写对,其实只是忘了加print。
表达式是语言的“造句单位”,函数、条件判断、循环里的条件,本质上都是在算各种表达式的值。D2这天不需要把所有运算符背得滚瓜烂熟,但至少要保证看到一段代码时,能说出“它先算了什么、再把结果赋给了谁”。
4. 输入输出与注释:和程序对话的基础姿势
4.1 input() 的返回值和 print() 的格式化输出
前两天的程序,和用户沟通基本靠两个函数:input()和print()。input()负责从键盘接收文本,括号里可以放一段提示文字:
name = input("请输入你的名字:") age = input("请输入你的年龄:")这里必须刻进脑子一句话:input()返回的一定是字符串。哪怕你输入的是数字,它返回的也是"25"这样的字符串。所以下面这段代码一定会出问题:
age = input("请输入你的年龄:") next_year_age = age + 1 print(next_year_age)因为"25" + 1会报TypeError: can only concatenate str (not "int") to str,意思是字符串只能跟字符串拼接,不能直接加整数。正确做法是先转换:
age = int(input("请输入你的年龄:")) next_year_age = age + 1 print(next_year_age)print()则比你想的更灵活一点。它默认会打印多个参数并用空格分隔,结尾自动换行。你还可以用sep和end控制分隔符和结尾:
print(1, 2, 3, sep="-", end="!\n") # 输出:1-2-3!实际项目中我最喜欢的是f-string格式化输出,简洁清楚。Python 3.6版本以上都支持:
name = "小明" age = 18 print(f"我叫{name},今年{age}岁。")花括号里可以直接放变量名,甚至放表达式,比如{age + 1}。写出来的代码一眼就能看出最终输出长什么样,比用+拼接字符串舒服太多。
4.2 注释:写给未来自己看的说明书
注释不会影响程序运行,它是给人类看的。单行注释用#开头:
# 计算平均分 total = 90 + 85 + 88 avg = total / 3需要写多行说明时,可以用三引号字符串放在文件开头,Python也会忽略它:
""" 本文件用于D2语言元素练习 运行前请确认输入的是数字 """严格来说,Python没有“多行注释”语法,三引号字符串在程序顶层不被使用时相当于注释,但更标准的做法是每行前面加#,或者把三引号字符串用作函数、模块的文档说明。D2阶段先会用#就够了。
注释不是越多越好。我见过有人把x = 1下面写一行“把1赋值给x”,这等于废话。好的注释应该说明“为什么这样写”,而不是“写了什么”。比如:
# 用 float 而不是 int,是因为用户输入的可能带小数 height = float(input("请输入身高:"))这条注释记录了你的设计意图,未来的你自己看到后才能知道当初为什么要这么处理。
5. 实操练习:用 D2 的语言元素拼出一个小程序
5.1 练习目标:求三角形面积
理论看完必须动手。D2最合适的小练习,是用之前的语言元素做一个“输入三角形底和高,输出面积”的小程序。这个练习不涉及循环、函数、异常处理,正好把变量、类型转换、算术运算、输入输出全部串起来。
公式很简单:三角形面积 = 底 × 高 ÷ 2。注意底和高可能是小数,所以要用float()转换,不能只想着整数。
我给自己定的目标:
- 用
input()接收底和高。 - 做类型转换。
- 用算术运算符计算面积。
- 用
print()输出结果。 - 全程加适量注释。
5.2 完整代码和逐步拆解
新建D2_triangle.py,把我的练习代码贴进去:
# 输入三角形的底和高,输出面积 base = input("请输入三角形的底:") height = input("请输入三角形的高:") # input 返回的是字符串,必须转成浮点数才能计算 base = float(base) height = float(height) # 三角形面积公式 area = base * height / 2 print(f"底为{base}、高为{height}的三角形,面积是{area}")代码一共四步:
- 先用
input()读入两个数据。此时base和height是字符串。 - 用
float()把它们转成浮点数。如果用户输入的是abc,这步会报ValueError,但D2阶段先不做异常处理,知道有这回事就行。 - 用
base * height / 2计算面积,Python会按优先级先乘后除。 - 用f-string把结果输出。
运行一遍,效果是这样的:
请输入三角形的底:5 请输入三角形的高:3.2 底为5.0、高为3.2的三角形,面积是8.0注意输出里出现了5.0而不是5,因为float("5")得到的是浮点数5.0。如果想输出格式更干净,可以在f-string里控制小数位:
print(f"面积是{area:.2f}")这样不管面积是多少,都只保留两位小数。
5.3 运行结果和扩展想法
这个小程序虽然简单,但它是你第一次真正“把用户输入变成计算结果”的完整闭环。我建议在此基础上做两个扩展:
第一个扩展是计算圆的面积。把公式换成π * r * r,可以临时用3.14159代替π。这个扩展考验的是你对浮点数和表达式组合的熟练度。
第二个扩展是加一层判断。如果用户输入的底或高小于等于0,就提示“输入不合法”,否则再计算。这需要用到比较运算符和if语句:
if base <= 0 or height <= 0: print("底和高必须大于0") else: area = base * height / 2 print(f"面积是{area:.2f}")这算是提前碰了一下条件判断,但核心还是语言元素。先写基础版,再扩展,是自学最稳的节奏。
6. 常见问题与排查技巧实录
6.1 新手最容易踩的五个坑
D2这天的知识点少,但每个点都能延伸出一堆报错。我把最常踩的五个坑按真实频率排了个序。
第一个坑:把==写成=
在if条件里,很多新手会写if score = 60。解释器会告诉你SyntaxError: invalid syntax,因为该写判断的地方被写成了赋值。我自己的排查方法是:看到SyntaxError先把行号附近代码的所有等号数一遍,看有没有单等号出现在条件位置。
第二个坑:int("3.14")直接崩
整数转换函数只接受“整数字符串”。想转换带小数点的文本,必须int(float("3.14")),或者干脆用float("3.14")。这个坑几乎人人必踩一次,踩完就记住了。
第三个坑:忘了input()返回字符串
从键盘读进来的数字,如果不做转换就直接做算术,常见的报错是TypeError: unsupported operand type(s) for +: 'int' and 'str'。排查套路是先看右边报错里提到了什么类型,然后去代码里找对应的变量,判断它到底是不是字符串。
第四个坑:变量名不规范导致各种诡异现象
给变量起名1number会直接报错,用print当变量名会突然让print()失效。这些问题的共同特征是“看起来语法没错,但运行结果莫名其妙”。养成好习惯是关键,变量名宁可长一点,也不能和关键字、内置函数冲突。
第五个坑:浮点数并不是精确小数
0.1 + 0.2在Python里等于0.30000000000000004,这不是Python的bug,而是二进制浮点表示导致的精度问题。D2不需要深究,但要知道错误来源,避免以后在钱相关计算里直接拿浮点数做等值判断。方案是显示时格式化小数位,或后续学Decimal。
6.2 快速排查速查表
初学者看到报错第一反应是慌,其实大部分报错都可以按症状查表定位:
| 报错或现象 | 可能原因 | 处理方式 |
|---|---|---|
NameError: name 'xxx' is not defined | 变量名拼写错、未赋值 | 检查变量名是否一致,先赋值再使用 |
TypeError: can only concatenate str (not "int") to str | 字符串和整数直接拼接 | 用str()转换,或改用f-string |
TypeError: unsupported operand type(s) for +: 'int' and 'str' | input()返回字符串,没做类型转换 | 用int()或float()转换后再运算 |
ValueError: invalid literal for int() ... | int()收到了非整数文本 | 用float(),或先检查输入内容 |
SyntaxError: invalid syntax | 关键字写错、=和==混用、缺冒号 | 检查报错行附近的符号 |
IndentationError: unexpected indent | 缩进不正确 | 统一用4个空格缩进,不要混用Tab |
这张表可以打印出来贴在显示器旁边,前两周写代码遇到报错,先对照一遍,比反复百度效率高得多。
6.3 自测清单
最后,我给自己列了五道自测题,写完这张清单,D2就算真正过关了:
- 写一个程序,把自己的姓名放在一个变量里,年龄放在另一个变量里,用
type()分别打印它们的类型。 - 让用户输入两个数字,打印它们的和、差、积、商,注意使用浮点数转换。
- 输入一个三位数,用整除
//和取余%算出百位、十位、个位,并求和。 - 用比较运算符判断一个数是否在0到100之间,并用
print()输出布尔结果。 - 给上面的代码加上必要的注释,解释关键步骤为什么这样写。
做完这几题,语言元素这部分就真的滚了一遍。
说实话,D2这天内容并不多,但它是整个Python自学路线里第一个“分水岭”。我在实际学习时,最大的感受是很多错误当天不解决,后面会一而再再而三地回来找你。比如input()返回字符串这件事,我到了D15写循环读文件时还在犯。所以,别急着往前赶,把每个示例敲到手指形成肌肉记忆,把每次报错当作一次免费的教学。如果今天只能记住一句话,那就记这句:一切来自键盘的输入,在你明确转换类型之前,都只是字符串。