第5章 基础语法:数据类型
本章介绍 Python 的内置数据类型及其行为。先总览各类型的用途,再依次讲解整数、浮点数、复数、布尔值、字符串与空值None的创建方式和常用操作,并重点说明浮点数的精度问题与字符串的不可变性;随后说明可变对象与不可变对象在赋值和修改时的差异,最后介绍使用type()与isinstance()判断类型的方法。
5.1 数据类型
5.1.1 类型概览
Python 中的每个对象都有类型。初学阶段常见的内置类型如下:
| 类别 | 类型 | 示例 | 可变性 |
|---|---|---|---|
| 整数 | int | 10、-3、0b1010 | 不可变 |
| 浮点数 | float | 3.14、1.2e3 | 不可变 |
| 复数 | complex | 2 + 3j | 不可变 |
| 布尔值 | bool | True、False | 不可变 |
| 字符串 | str | "Python"、'你好' | 不可变 |
| 字节序列 | bytes | b"Python" | 不可变 |
| 空值 | NoneType | None | 不可变 |
| 列表 | list | [1, 2, 3] | 可变 |
| 元组 | tuple | (1, 2, 3) | 不可变 |
| 字典 | dict | {"name": "张三"} | 可变 |
| 集合 | set | {1, 2, 3} | 可变 |
5.1.2 整数int
Python 使用int表示整数,主要具有以下特点:
- 整数可以是正数、负数或零;
- 在可用内存允许的范围内,
int可以表示任意大小的整数; - Python 不会根据整数大小划分不同的公开类型,所有整数都属于
int; - 解释器可能缓存或复用某些整数对象,但这是实现细节,不能作为程序逻辑的依据;
- 比较整数值是否相等应使用
==,而不是用于比较对象身份的is。
下面的代码演示不同整数的创建和数值比较:
"""演示 Python 整数的创建和数值比较。""" # 创建正数、负数、零和大整数 positive = 100 negative = -20 zero = 0 large_number = 10**100 print(f"正整数:{positive}") print(f"负整数:{negative}") print(f"零:{zero}") print(f"大整数:{large_number}") # 比较整数值 first = 1_000 second = int("1000") print(f"两个整数的值是否相等:{first == second}")5.1.3 浮点数float
Python 使用float表示浮点数,主要具有以下特点:
- 可以使用小数形式或科学计数法创建浮点数;
- 大多数十进制小数无法用有限位二进制精确表示,运算结果可能存在微小误差;
- 判断两个浮点数是否足够接近时,可以使用
math.isclose(); - 需要精确十进制运算时,可以使用
decimal.Decimal,并优先通过字符串创建对象; - 使用
Decimal时仍需根据业务需求明确精度和舍入规则。
下面的代码演示浮点数的创建、误差判断和精确十进制运算:
"""演示 Python 浮点数的创建、误差判断和精确十进制运算。""" import math import decimal # 使用小数形式和科学计数法创建浮点数 price = 19.9 distance = 1.5e3 print(f"商品价格:{price}") print(f"科学计数法表示的距离:{distance}") # 观察二进制浮点数的表示误差 sum_result = 0.1 + 0.7 print(f"0.1 + 0.7 的结果:{sum_result}") print(f"直接与 0.8 比较:{sum_result == 0.8}") print(f"是否足够接近 0.8:{math.isclose(sum_result, 0.8)}") # 使用 Decimal 进行精确的十进制运算 exact_result = decimal.Decimal("0.1") + decimal.Decimal("0.7") print(f"Decimal 运算结果:{exact_result}")5.1.4 复数complex
Python 使用complex表示复数,主要具有以下特点:
- 复数由实部和虚部组成,例如
2 + 3j; - Python 使用
j或J标记虚部,不使用数学中常见的i; - 可以直接使用复数字面量,也可以通过
complex()创建复数; real和imag属性分别获取实部和虚部,conjugate()返回共轭复数;- 复数支持相等性比较,但不支持使用
<、>等运算符比较大小。
下面的代码演示复数的创建和常用操作:
"""演示 Python 复数的创建和常用操作。""" # 使用复数字面量和 complex() 创建复数 literal_number = 2 + 3j constructed_number = complex(2, 3) print(f"复数字面量:{literal_number}") print(f"complex() 创建的复数:{constructed_number}") print(f"两个复数的值是否相等:{literal_number == constructed_number}") # 获取复数的实部、虚部和共轭复数 print(f"实部:{literal_number.real}") print(f"虚部:{literal_number.imag}") print(f"共轭复数:{literal_number.conjugate()}")5.1.5 布尔值bool与真值判断
Python 使用bool表示布尔值,主要具有以下特点:
- 布尔类型只有
True和False两个值,常用于条件判断; bool()可以获取对象的真值;None、False、数值零以及空字符串和空容器等对象为假,其他大多数对象为真;bool是int的子类,True和False在数值运算中分别表现为1和0;- 布尔值的主要用途是表达真假,不应过度依赖它的整数特性。
下面的代码演示布尔运算、布尔值的整数特性以及常见对象的真值:
"""演示 Python 布尔值和对象的真值判断。""" # 使用布尔值表示条件 is_adult = True has_ticket = False print(f"是否允许入场:{is_adult and has_ticket}") # bool 继承自 int:True/False 参与数值运算时按 1 和 0 处理 print(f"True 是否属于 bool:{isinstance(True, bool)}") print(f"True 是否属于 int:{isinstance(True, int)}") print(f"True + True 的结果:{True + True}") # 使用 bool() 查看常见对象的真值 values = [None, False, 0, 0.0, 0j, "", [], (), {}, set(), "Python", [0]] for value in values: print(f"{value!r} 的真值:{bool(value)}")5.1.6 字符串str
字符串是由 Unicode 字符组成的不可变序列,主要具有以下特点:
- 可以使用单引号、双引号或三引号创建字符串;
- 单引号和双引号没有功能差异,可以根据字符串内容选择更易读的形式;
- 三引号可以创建跨越多行的字符串;
- 反斜杠
\用于引入转义序列,r前缀创建的原始字符串会保留大多数反斜杠; - 字符串不可变,修改字符串的操作会创建新字符串;
- 比较字符串内容应使用
==,不应依赖字符串驻留等解释器优化细节。
常用转义序列如下:
| 转义序列 | 含义 |
|---|---|
\\ | 一个反斜杠 |
\' | 单引号 |
\" | 双引号 |
\n | 换行 |
\t | 水平制表符 |
\r | 回车 |
\b | 退格 |
\u4F60 | 使用 4 位十六进制表示字符 |
下面的代码演示字符串的创建、转义、原始字符串和不可变性:
"""演示 Python 字符串的创建和常用操作。""" # 使用单引号、双引号和三引号创建字符串 single_quoted = 'Python' double_quoted = "你好" multiline = """第一行 第二行""" sentence1 = "I'm learning Python." sentence2 = '他说:“你好!”' print(f"单引号字符串:{single_quoted}") print(f"双引号字符串:{double_quoted}") print(f"包含单引号的句子:{sentence1}") print(f"包含双引号的句子:{sentence2}") print("多行字符串:") print(multiline) # 使用转义序列和原始字符串 profile_text = "昵称:小林\n语言:Python" path = r"C:\new_folder\test.txt" print("包含换行符的字符串:") print(profile_text) print(f"原始字符串:{path}") # 字符串操作会创建新字符串 language = "python" upper_language = language.upper() print(f"原字符串:{language}") print(f"新字符串:{upper_language}")注意:原始字符串仍需遵守字符串定界规则,不能以奇数个反斜杠结尾。
5.1.7 空值None
Python 使用None表示空值,主要具有以下特点:
None常用于表示“没有值”“尚未设置”或“结果不存在”;None是NoneType类型唯一的实例;None在条件判断中为假;- 判断对象是否为
None时,应使用is或is not; - 不能用
if not value代替对None的精确判断,因为数值零、空字符串和空容器也为假。
下面的代码演示None的类型、真值和正确判断方式:
"""演示 Python 空值 None 的特点和判断方式。""" result = None print(f"None 的类型:{type(result)}") print(f"None 的真值:{bool(result)}") # 使用 is 判断对象是否为 None if result is None: print("暂时没有结果") # 对比 None 与其他假值 values = [None, 0, "", []] for value in values: print(f"{value!r} 是否为 None:{value is None}")5.1.8 可变对象与不可变对象
可变性用于描述对象创建后,其内部状态能否原地修改,主要具有以下特点:
- 列表、字典和集合等属于可变对象,可以在不替换对象的情况下修改内部状态;
- 整数、浮点数、布尔值、复数、字符串和元组等属于不可变对象,所谓的“修改”通常会创建新对象;
- 可变性是对象的特性,而不是变量的特性,变量始终可以重新绑定到其他对象;
- 多个变量引用同一个可变对象时,通过任意一个变量修改对象,其他变量也能看到变化;
- 将某个变量重新赋值,只会改变该变量的绑定关系,不会修改它之前引用的对象。
下面的代码演示修改可变对象、重新绑定变量和操作不可变对象的区别:
"""演示 Python 可变对象与不可变对象的区别。""" # 列表是可变对象,shared_numbers 与 numbers 引用同一个列表 numbers = [1, 2] shared_numbers = numbers shared_numbers.append(3) print(f"numbers:{numbers}") print(f"shared_numbers:{shared_numbers}") print(f"是否引用同一个对象:{numbers is shared_numbers}") # 重新赋值只会改变 shared_numbers 的绑定关系 shared_numbers = [4, 5] print(f"重新赋值后的 numbers:{numbers}") print(f"重新赋值后的 shared_numbers:{shared_numbers}") print(f"是否仍引用同一个对象:{numbers is shared_numbers}") # 字符串是不可变对象,拼接会创建新字符串并重新绑定变量 language = "Py" original_language = language language += "thon" print(f"原字符串:{original_language}") print(f"拼接后的字符串:{language}") print(f"是否引用同一个对象:{language is original_language}")注意:元组本身不可变,但如果元组中包含列表等可变对象,这些可变对象的内部状态仍然可以修改。
5.1.9type()与isinstance()类型判断
Python 提供type()和isinstance()用于查看或判断对象的类型,主要具有以下特点:
type(value)返回对象的直接类型;type(value) is SomeType只判断对象的直接类型是否为SomeType;isinstance(value, SomeType)会同时考虑SomeType及其子类;isinstance()的第二个参数可以是类型元组,用于一次判断多种类型;- 业务代码通常优先使用更加灵活的
isinstance(),也应避免在没有必要时过度限制对象的具体类型。
二者的主要区别如下:
| 写法 | 是否考虑子类 | 常见用途 |
|---|---|---|
type(value) is SomeType | 否 | 必须确认对象的直接类型 |
isinstance(value, SomeType) | 是 | 常规类型判断,通常更加灵活 |
下面的代码演示type()与isinstance()在类型判断中的不同表现:
"""演示 type() 与 isinstance() 的不同表现。""" # 比较运算的结果是布尔值 int_score = 85 value = int_score >= 60 # type() 返回对象的直接类型 print(f"value 的直接类型:{type(value)}") print(f"value 的直接类型是否为 bool:{type(value) is bool}") print(f"value 的直接类型是否为 int:{type(value) is int}") # isinstance() 会考虑类型的继承关系 print(f"value 是否属于 bool:{isinstance(value, bool)}") print(f"value 是否属于 int:{isinstance(value, int)}") print(f"value 是否属于 int 或 float:{isinstance(value, (int, float))}")