Python 内置的数字、字符串、字节序列和布尔值看似简单,却决定了数据如何计算、比较、编码与传输。理解这些类型的行为,能减少浮点误差、文本编码异常和隐式类型转换带来的问题。
数字不只有整数和小数
Python 常用的数字类型包括 int、float 和 complex。
int表示整数,大小通常不受固定 32 位或 64 位范围限制,而是受可用内存约束。float表示浮点数,适合一般科学计算,但不能精确表示所有十进制小数。complex表示复数,使用j标记虚部,例如3 + 4j。
integer_value = 42
float_value = 0.1 + 0.2
complex_value = 3 + 4j
print(type(integer_value), integer_value)
print(type(float_value), float_value)
print(type(complex_value), complex_value)
print(complex_value.real, complex_value.imag)
运行后通常会看到 0.1 + 0.2 并不严格等于 0.3:
print(0.1 + 0.2 == 0.3) # False
这是二进制浮点表示的结果,而不是 Python 的计算错误。比较浮点数时,可以使用 math.isclose():
import math
result = 0.1 + 0.2
print(math.isclose(result, 0.3, rel_tol=1e-9, abs_tol=0.0)) # True
如果业务涉及金额,可以这样实践:使用 decimal.Decimal,并通过字符串构造十进制数,避免先引入浮点误差。
from decimal import Decimal
price = Decimal("19.90")
quantity = 3
total = price * quantity
print(total) # 59.70
字符串表示文本,字节表示编码后的数据
str 用于保存 Unicode 文本,bytes 用于保存原始字节。两者表面上都像序列,但不能直接拼接或比较为相同内容。
text = "Python 数据类型"
payload = text.encode("utf-8")
restored = payload.decode("utf-8")
print(text)
print(payload)
print(restored)
print(text == restored) # True
这里有一条实用边界:
- 用户输入、JSON 字段和程序内部文本通常使用
str。 - 文件内容、网络响应体、图片和加密数据在底层通常表现为
bytes。 - 从文本变成字节时调用
encode();从字节恢复文本时调用decode()。
编码和解码必须采用兼容的字符编码,否则会出现乱码或 UnicodeDecodeError。例如,下面的字节来自 UTF-8,就不应该按 ASCII 解码:
message = "你好".encode("utf-8")
try:
print(message.decode("ascii"))
except UnicodeDecodeError as exc:
print(f"解码失败: {exc}")
str 和 bytes 都是不可变对象。所谓“修改字符串”,实际上会创建一个新对象:
name = "python"
updated_name = name.capitalize()
print(name) # python
print(updated_name) # Python
处理大量二进制数据且需要原地修改时,可以考虑可变的 bytearray:
packet = bytearray(b"ABC")
packet[0] = ord("Z")
print(packet) # bytearray(b'ZBC')
布尔值也是一种特殊的数字
Python 的布尔类型只有两个值:True 和 False。它常用于条件判断,同时也是 int 的子类:
print(isinstance(True, bool)) # True
print(isinstance(True, int)) # True
print(True + True + False) # 2
这种设计让布尔值可以参与统计。例如,可以直接计算一组条件中有多少项成立:
checks = [
len("python") > 3,
10 % 2 == 0,
"x" in "data",
]
passed = sum(checks)
print(f"通过 {passed}/{len(checks)} 项检查")
不过,能把布尔值当整数使用,不代表总应该这样做。业务代码如果需要表达计数,显式转换成 int 或使用清晰的变量名,通常更容易维护。
条件语句还会对其他类型执行真假判断。常见的假值包括:
False- 数字零,如
0、0.0和0j - 空字符串
"" - 空字节串
b"" - 空容器,如
[]、{}和set() None
values = [0, 1, "", "Python", b"", b"data", None]
for value in values:
print(repr(value), "=>", bool(value))
需要注意,字符串 "False" 并不是假值,因为它是一个非空字符串:
print(bool("False")) # True
print(bool("0")) # True
读取环境变量或配置文件时,不要直接用 bool(text) 解析开关。可以这样实践:
def parse_bool(value: str) -> bool:
normalized = value.strip().lower()
if normalized in {"true", "1", "yes", "on"}:
return True
if normalized in {"false", "0", "no", "off"}:
return False
raise ValueError(f"无法识别的布尔值: {value!r}")
print(parse_bool("YES")) # True
print(parse_bool(" off ")) # False
一段可直接运行的类型检查程序
将下面代码保存为 basic_types.py,然后执行 python basic_types.py。它集中演示类型识别、文本编码和真假判断。
from typing import Any
def describe(value: Any) -> None:
print(
f"value={value!r:<20} "
f"type={type(value).__name__:<8} "
f"truthy={bool(value)}"
)
values = [
42,
3.14,
2 + 5j,
"Python",
"",
b"Python",
True,
False,
]
for item in values:
describe(item)
text = "类型"
data = text.encode("utf-8")
print("编码结果:", data)
print("解码结果:", data.decode("utf-8"))
运行命令:
python basic_types.py
使用这些类型时的检查清单
在实际项目中,可以用以下问题快速确认类型选择是否合理:
- 这是需要计算的数字,还是只具有数字外观的标识符?手机号、邮编和订单号通常应保存为字符串。
- 是否要求精确的十进制计算?如果是金额等场景,应评估
Decimal,不要默认使用float。 - 当前变量代表人类可读文本还是原始字节?跨越文件和网络边界时,要明确编码格式。
- 布尔值是否来自字符串配置?如果是,应显式解析,而不是依赖非空字符串的真值。
- 是否在混合不同类型?Python 不会自动把
"3"当作数字3,转换应当明确并处理失败情况。
基础类型本身并不复杂,真正容易出错的是类型边界。把数字精度、字符编码和真假规则写清楚,程序的数据流就会稳定得多。