类型与变量
这一课你将能做到
- 熟练使用 int、float、bool、str、None 五种基础类型,并用
type() 验证任何一个值的类型
- 说清 Python 变量是「贴在对象上的名字标签」,解释赋值和 Java 引用的异同
- 正确完成 int/float/str/bool 之间的显式转换,避免
input() 返回字符串这类经典坑
为什么要学
Python 变量不用声明类型——这一行 x = 10,下一行 x = "hello" 也不报错。自由归自由,但类型一直在幕后管着事:1 + "a" 会炸、"3" > 10 在 3.12 里直接 TypeError、0.1 + 0.2 != 0.3。不理解类型系统,报错都看不懂。
人话:变量就像便利贴,值是盒子里的东西。便利贴本身没有类型(今天贴盒子 A,明天贴盒子 B 都行),但盒子里装的东西有类型。type() 就是「打开盒子看一眼」的工具。
先建立图像
Java: int x = 10; → 盒子造出来就是 int 型,焊死了
Python: x = 10 → 便利贴 x 贴到 int 对象 10 上
x = "hello" → 撕下来贴到 str 对象上,x 本身没变
五种基础类型一张表:
| 类型 | 字面量示例 | 用途 | type() 输出 |
|---|
| int | 10, -3, 10**100 | 整数,无长度上限 | <class 'int'> |
| float | 3.14, 1e-3 | 浮点数(双精度) | <class 'float'> |
| bool | True, False | 真假判断 | <class 'bool'> |
| str | 'abc', "你好" | 文本(第 7 课专讲) | <class 'str'> |
| NoneType | None | 「还没有值」的唯一值 | <class 'NoneType'> |
跟着做
步骤 1:变量赋值与 type() 初体验
新建 types_demo.py:
age = 25
price = 19.99
name = "CodeRoadMap"
is_vip = True
memo = None
print(type(age)) # <class 'int'>
print(type(price)) # <class 'float'>
print(type(name)) # <class 'str'>
print(type(is_vip)) # <class 'bool'>
print(type(memo)) # <class 'NoneType'>
# 一个变量先后贴不同的类型,完全合法
x = 100
x = "现在是字符串"
print(type(x)) # <class 'str'>
运行:python types_demo.py。五行 class 输出全部符合注释,说明赋值即声明、类型跟着值走。
步骤 2:同一行赋多个值与交换
a, b = 1, 2 # 同时赋值
print(a, b) # 1 2
a, b = b, a # 交换,不需要临时变量
print(a, b) # 2 1
步骤 3:数字运算的规则
print(7 + 2) # 9 int + int → int
print(7 / 2) # 3.5 / 永远返回 float
print(7 // 2) # 3 // 整除(向下取整)
print(7 % 2) # 1 % 取余
print(7 ** 2) # 49 ** 幂
print(2 ** 64) # 18446744073709551616 int 无溢出
print(0.1 + 0.2) # 0.30000000000000004 浮点精度问题
9
3.5
3
1
49
18446744073709551616
0.30000000000000004
三个要点:/ 结果永远是 float(6 / 2 得 3.0);int 不会溢出(对比 Java 的 Integer.MAX_VALUE);浮点精度是二进制表示的固有现象,钱相关计算用整数(分)或 decimal 模块。
步骤 4:显式类型转换
s = "123"
n = int(s) # str → int
print(n + 1) # 124
f = float("3.14") # str → float
print(f * 2) # 6.28
text = str(999) # int → str
print(text + " 分") # 999 分
print(int(3.99)) # 3 float → int 直接截断,不四舍五入
print(int(True)) # 1 bool 就是特殊的 int
print(bool(0)) # False 0 → False
print(bool(42)) # True 非 0 → True
print(bool("")) # False 空字符串 → False
print(bool("0")) # True 非空字符串(含 "0")→ True
124
6.28
999 分
3
1
False
True
False
True
int(3.99) 得 3 不是 4——int() 对 float 是截断不是四舍五入,要四舍五入用 round(3.99)。
步骤 5:input() 经典坑——一切输入皆字符串
raw = input("请输入年龄:") # 键盘输入 18
print(type(raw)) # <class 'str'> !
# print(raw + 1) # TypeError,字符串 + 数字
age = int(raw) # 必须手动转换
print(age + 1) # 19,明年年龄
请输入年龄:18
<class 'str'>
19
这是初学者第一大坑:input() 永远返回 str,做数学运算前必须 int() / float()。
步骤 6:is 判断 None
memo = None
if memo is None: # 判 None 的标准写法
print("还没有备注")
x = 1000
print(x == 1000) # True,值相等
print(x is 1000) # 语法上能跑但别这么用:
# is 比较的是对象身份不是值
规则一句话:比数值用 ==,判 None 用 is None。
讲清楚要点
- 变量是名字,不是盒子:Python 变量是「对象引用」。赋值
a = b 复制的是引用不是对象本身——这决定了后面学可变对象(list)时的别名现象。
- 动态类型 + 强类型:类型不声明(动态),但不会偷偷帮你
"1" + 1(强类型,直接 TypeError)。对比 JavaScript 是弱类型,"1" + 1 得 "11"。
/ 与 // 必须分清:/ 真除法恒返回 float;// 向下取整。-7 // 2 是 -4 不是 -3(向下取整的意思)。
- int 无限精度,float 有精度:Python 的 int 想多大有多大(对比 Java 要 BigInteger);float 是 64 位双精度,
0.1 + 0.2 的经典问题源自二进制无法精确表示 0.1。
- bool 是 int 的子类:
True == 1、False == 0 成立,甚至能 sum([True, False, True]) 得 2——计数技巧。
- None 是对象不是「空指针错误」:它表示「刻意没有值」,函数没写 return 时返回的就是 None。判空永远
is None。
- f-string 里能直接调试:
print(f"{x=}") 输出 x=100(变量名和值一起打),3.8+ 的调试利器。
你可能会懵的地方
-
既然动态类型,为什么还要学类型?
动态类型只是「不用提前声明」,运行时每个值依然有确定类型,所有运算符行为都由类型决定。不懂类型 = 看不懂 TypeError = 调不了 bug。另外 3.5+ 支持类型注解(def f(x: int) -> str),大型项目都在用,学类型是前提。
-
is 和 == 到底差在哪?
== 比值(调用 __eq__),is 比身份(内存中是否同一个对象)。日常 99% 场景用 ==;唯一惯例是 x is None。小整数缓存(-5~256)会让 is 偶尔「碰巧」返回 True,千万别被误导。
-
为什么 0.1 + 0.2 不等于 0.3?
浮点数用二进制存,0.1 在二进制里是无限循环小数,只能近似存储。比较浮点数用 math.isclose(0.1 + 0.2, 0.3),或金额用 decimal.Decimal("0.1")。
-
int("12abc") 会怎样?
直接 ValueError: invalid literal for int() with base 10: '12abc'。转换失败不截断、不给 0。第 11 课会教用 try/except 兜住这种用户输入。
-
变量名有什么规矩?
字母/数字/下划线组成、不能以数字开头、区分大小写、不能用关键字(if、class 等)。PEP 8 风格:普通变量 snake_case,常量 MAX_RETRY 全大写。import keyword; print(keyword.kwlist) 可列出全部关键字。
错法对照
| 错法 | 问题 | 正解 |
|---|
age = input() 后直接算术运算 | input 返回 str,TypeError | age = int(input()) |
int(3.99) 当四舍五入用 | int() 是截断,得 3 | 四舍五入用 round(3.99) |
if x == None: | 风格与语义都不标准 | if x is None: |
用 is 比较数值是否相等 | 靠缓存「碰巧」对,不可靠 | 比值一律 == |
| 金额用 float 累加 | 精度误差累积 | 整数存分,或 decimal.Decimal |
print("结果:" + 42) | str + int 直接炸 | f"结果:{42}" 或 str(42) |
卡点急救
- TypeError: unsupported operand type(s) for +: 'int' and 'str':两边类型不一致。
type() 打印两边各是什么,用 int() / str() 转到一致。
- ValueError: invalid literal for int():字符串不是纯数字。先
s.strip() 去空格,确认内容,再转换;用户输入场景包 try/except(第 11 课)。
- float 相加结果很长一串 4:正常精度现象。展示用
round(x, 2),比较用 math.isclose,金额换 Decimal。
- 变量打印出来是 None:多半把「函数返回 None」赋给了它,如
x = print("hi") 或 x = list.sort()(原地操作返回 None)。查该函数是「返回新值」还是「原地修改」。
面试常问
-
Python 是动态类型还是强类型?
两者都是。动态类型指变量无需声明类型、类型随值走;强类型指不同类型之间不会隐式转换参与运算("1" + 1 报 TypeError)。对比 JavaScript 是「动态 + 弱类型」。
-
Python 变量的本质是什么?
名字到对象的引用(绑定)。赋值不拷贝对象,只建立名字→对象的引用。由此可解释可变对象的共享修改、函数传参的「传对象引用」行为。id(x) 可查看对象身份。
-
is 与 == 的区别?
is 比较对象 id(是否同一对象),== 比较值(__eq__)。惯例:is 只用于 None 判断和单例检测,其余用 ==。
-
为什么 0.1 + 0.2 != 0.3?怎么解决?
IEEE 754 双精度浮点的二进制表示误差。解决:math.isclose() 做近似比较;金融场景用 decimal.Decimal(十进制精确)或以「分」为单位的整数运算。
-
Python 的 int 会溢出吗?
不会,int 是任意精度实现(内部按需扩展存储),2 ** 1000 直接可算。代价是超大数运算比定宽整数慢。
自测三问
7 / 2、7 // 2、7 % 2、-7 // 2 各是多少?
bool("0")、bool(0)、bool([])、int(True) 各是多少?
- 从
input() 拿到的值要做加法,中间必须补哪一步?忘了会报什么错?
小结一句话
Python 变量是贴在对象上的名字,类型跟着值走;记住 / 出 float、input 出 str、None 用 is、float 有精度,基础类型就算打通了。
延伸
- 官方教程 — 数字
- 内置类型参考
- 下一课预告:条件与循环——if/elif/else、for/while、range 与 break/continue,程序开始有「脑子」了。