Python 是动态类型语言,变量的数据类型在运行时自动推断,无需事先声明。掌握核心数据类型有助于写出更安全、可读性更好的代码。常见类型大致可分为:
int、float、complexstrlist、tuple、rangedictset、frozensetboolbytes、bytearray、memoryviewNoneType此外 Python 允许定义自定义类,以及通过迭代器、生成器实现惰性计算。
Python 中所有数据类型都继承自 object,形成统一的类型体系:
Python 采用"一切皆对象"的设计哲学,所有类型都继承自 object,这带来以下好处:
__str__、__eq__、__hash__ 等方法isinstance(obj, object) 对任意对象都返回 Trueint、float、bool、str、tuple、frozenset、bytes、NoneTypelist、dict、set、bytearray(以及指向可变对象的 memoryview)避免在函数参数中使用可变类型作为默认值,例如 def f(a=[]): ...。如需默认空列表,使用 None 再在函数体中初始化:def f(a=None): a = [] if a is None else a
错误示例:
def add_item(item, my_list=[]):
"""错误:默认参数在函数定义时求值,所有调用共享同一列表"""
my_list.append(item)
return my_list
print(add_item(1)) # 输出: [1]
print(add_item(2)) # 输出: [1, 2] (列表被共享和修改)正确示例:
def add_item_correct(item, my_list=None):
"""正确:使用 None 作为哨兵值,每次调用创建新列表"""
if my_list is None:
my_list = []
my_list.append(item)
return my_list
print(add_item_correct(1)) # 输出: [1]
print(add_item_correct(2)) # 输出: [2] (每次调用都创建新列表)Python 在混合运算时会自动进行类型提升:
表示整数值,没有小数部分。int 无固定长度限制,理论上只受系统内存约束。
在 Python 2 中,int 是固定精度的(通常 32 位),超出范围会自动转换为 long 类型。Python 3 统一了这两种类型:
int (32位) → long (任意精度)int 直接支持任意精度,无需 long这种设计简化了语言,程序员无需关心整数溢出问题。底层实现使用"变长数组"存储大整数,自动扩展内存。
a = 10
b = -5计算机由于使用二进制,有时用十六进制表示整数比较方便,十六进制用 0x 前缀和 0-9、a-f 表示,例如:0xff00,0xa5b4c3d2,等等。书写很大的数时,可使用下划线将其中的数字分组,使其更清晰易读。当打印这种使用下划线定义的数时,Python 不会打印其中的下划线:
universe_age = 14_000_000_000
print(universe_age) # 14000000000这是因为存储这种数时,Python 会忽略其中的下划线。将数字分组时,即便不是将每三位分成一组,也不会影响最终的值。在 Python 看来 1000 与 1_000 没什么不同,1_000 与10_00 也没什么不同。这种表示法适用于整数和浮点数,但只有 Python 3.6 和更高的版本支持
# Python int 可以表示任意大的整数,不会溢出
# 计算 2 的 100 次方
big_num = 2 ** 100
print(f"2^100 = {big_num}") # 1267650600228229401496703205376
# 计算更大的数
huge_num = 10 ** 1000 # 远超古戈尔(Googol = 10^100)
print(f"10^1000 有 {len(str(huge_num))} 位数字") # 1001 位
# 对比其他语言的溢出行为
# C/Java 中 int 最大值约为 2.1 * 10^9
# Python 无此限制,只受内存约束
import sys
print(f"当前整数占用字节数: {sys.getsizeof(big_num)}") # 40 字节(64 位 CPython 3.14)
print(f"更大整数占用字节数: {sys.getsizeof(huge_num)}") # 468 字节(64 位 CPython 3.14)表示带有小数部分的实数。使用双精度浮点数表示,可能存在精度误差。
JavaScript 采用 IEEE 754 双精度浮点数统一表示所有数字,这导致:
Python 保留 int 和 float 分离的设计:
int:任意精度,精确计算,适合计数、索引、大数运算float:IEEE 754 双精度,硬件加速,适合科学计算这种设计在精确性和性能之间取得平衡。
c = 3.14
d = -0.001从很大程度上说,使用浮点数时无须考虑其行为。只需输入要使用的数,Python 通常会按期望的方式处理它们。但需要注意的是,结果包含的小数位数可能是不确定的:
0.2 + 0.1 # 0.30000000000000004
3 * 0.1 # 0.30000000000000004所有语言都存在这种问题。就现在而言,暂时忽略多余的小数位数即可。如果业务必须保留精确小数,可使用 decimal.Decimal 或 fractions.Fraction 获得更高精度
将任意两个数相除时,结果总是浮点数,即便这两个数都是整数且能整除:
4/2 # 2.0在其他任何运算中,如果一个操作数是整数,另一个操作数是浮点数,结果也总是浮点数:
1 + 2.0 # 3.0
2 * 3.0 # 6.0
3.0 ** 2 # 9.0整数和浮点数在计算机内部存储的方式是不同的,整数运算永远是精确的,而浮点数运算则可能会有四舍五入的误差
使用 Decimal 进行精确计算:
from decimal import Decimal, getcontext
# 设置精度(可选,默认 28 位)
getcontext().prec = 50
# 浮点数计算的精度问题
print("浮点数计算:")
print(f" 0.1 + 0.2 = {0.1 + 0.2}") # 0.30000000000000004
print(f" 0.1 + 0.2 == 0.3: {0.1 + 0.2 == 0.3}") # False
# 使用 Decimal 进行精确计算
print("\nDecimal 精确计算:")
print(f" Decimal('0.1') + Decimal('0.2') = {Decimal('0.1') + Decimal('0.2')}") # 0.3
print(f" 结果 == Decimal('0.3'): {Decimal('0.1') + Decimal('0.2') == Decimal('0.3')}") # True
# 注意 - 必须用字符串构造 Decimal
# 错误方式:Decimal(0.1) 会先创建浮点数,再转换,精度已丢失
print(f"\n错误方式 Decimal(0.1): {Decimal(0.1)}") # 0.1000000000000000055511151231257827021181583404541015625
print(f"正确方式 Decimal('0.1'): {Decimal('0.1')}") # 0.1表示复数,包含实部和虚部。虚部用 j 或 J 表示
e = 2 + 3j
f = -1.5 - 4Jstr 表示文本数据,由一系列字符组成,支持单/双/三引号定义、索引切片、常用方法、格式化及编解码。
📚 详细教程见 08-字符串 —— 字符串的索引切片、常用方法、格式化(f-string)、str/bytes 编解码等完整内容。
s = 'Hello'
greeting = f"{s}, World!" # f-string 格式化
print(s[0], s[-1]) # H o(索引)
print(s[::-1]) # olleH(切片反转)有序且可变的集合,可包含不同类型元素,支持索引、切片、增删、排序、列表推导式。
📚 详细教程见 09-列表与元组 —— 列表的完整操作、元组、浅深拷贝等。
fruits = ['苹果', '香蕉', '橙子']
fruits.append('梨')
squares = [i*i for i in range(5)] # 列表推导式有序且不可变的集合,一旦创建内容不可更改,常用于不可变配置或函数一次返回多值。
coordinates = (10, 20)
a, b = (1, 2) # 打包与解包
t = (1,) # 单元素元组需要逗号不可变的数字序列,惰性求值、占用常量空间,常用于 for 循环:
numbers = range(0, 10, 2) # 生成 0, 2, 4, 6, 8
print(list(numbers))无序的键值对集合,键必须是不可变类型,支持快速查找、添加、删除、字典推导式。
📚 详细教程见 10-字典 —— 字典的 CRUD、视图遍历、collections 特殊字典等。
person = {'name': '张三', 'age': 25}
person.get('country', '中国') # 安全访问,带默认值
person.update({'age': 26})
square_map = {i: i*i for i in range(5)} # 字典推导式无序且不重复的元素集合,支持并集、交集、差集等数学运算,常用于去重。
📚 详细教程见 11-集合 —— 集合的完整操作、集合运算、推导式、frozenset 等。
A = {1, 2, 3}
B = {3, 4}
print(A | B) # 并集 {1,2,3,4}
print(list(set([1, 1, 2, 3]))) # 去重 [1, 2, 3]不可变的集合,创建后内容不可更改,可作为字典键或其他集合的元素:
fixed_set = frozenset([1, 2, 3])表示真 (True) 或假 (False) 的逻辑值。布尔值只有 True、False 两种值,在 Python 中可以直接用 True、False 表示布尔值(请注意大小写),也可以通过布尔运算计算出来:
is_valid = True
is_empty = FalsePython 的 bool 类型继承自 int,这是历史原因和实用主义的结合:
bool 类型,用 0 和 1 表示真假bool 作为 int 子类,旧代码无需修改True + True == 2,可以用于计数# bool 继承自 int 的证据
print(isinstance(True, int)) # True
print(True + True) # 2
print(True * 10) # 10
print(int(True)) # 1
print(int(False)) # 0布尔值可以用 and、or 和 not 运算:
and 运算是与运算,只有所有都为 True,and 运算结果才是Trueor 运算是或运算,只要其中有一个为 True,or 运算结果就是 Truenot 运算是非运算,它是一个单目运算符,把 True 变成 False,False 变成 True布尔值经常用在条件判断中,比如:
age = 20
if age >= 18:
print('adult')
else:
print('teenager')短路与返回值行为:
print([] or 'fallback') # 'fallback'
print('x' and 123) # 123(返回操作数本身)表示固定长度的字节序列
b 定义,如 b'hello'data = b'Hello World'# 从整数序列构造
print(bytes([65, 66, 67])) # b'ABC'
# 与字符串互转需显式编解码
text = '你好'
buf = text.encode('utf-8')
print(buf.decode('utf-8'))可变的字节序列,类似于 bytes,但可以修改。使用 bytearray() 函数创建,适合需要原地修改二进制数据的场景
mutable_data = bytearray(b'Hello')
mutable_data[0] = 72 # 修改字节# 追加、切片
mutable_data.append(33) # 添加 '!'
print(mutable_data[:2]) # bytearray(b'He')提供对其他二进制数据的内存访问视图,无需复制数据。支持高效的数据访问和操作
data = bytearray(b'Hello')
view = memoryview(data)print(view[0]) # 72(查看但不复制)
view[0] = 104 # 修改原数据为 'hello'表示空值或缺失值,只有一个值 None。常用于变量初始化或函数返回值表示无结果。None 不能理解为 0,因为 0 是有意义的,而 None 是一个特殊的空值。判断是否为 None 应使用 is/is not
result = NonePython 设计 NoneType 作为单独类型而非用 void 或 null 关键字,有以下原因:
None 有明确类型,可以进行类型检查None 对象,节省内存None 表示"无值",与 0、False、"" 等有意义的值区分None,便于判断# None 是单例
a = None
b = None
print(a is b) # True,指向同一对象
print(id(a) == id(b)) # True判断是否为 None:
if result is None:
print('空值')用户自定义的数据类型,通过类可以创建具有特定属性和方法的对象。支持面向对象编程,包括继承、封装、多态等特性
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def greet(self):
print(f"你好,我是{self.name},今年{self.age}岁。")
person = Person('李四', 30)
person.greet()可结合 dataclasses 简化数据类定义:
from dataclasses import dataclass
@dataclass
class User:
name: str
age: int实现迭代协议的对象,可以通过 next() 函数逐个返回元素。常用于遍历集合中的元素,只需实现 __iter__() 与 __next__() 方法即可自定义
my_list = [1, 2, 3]
iterator = iter(my_list)
print(next(iterator)) # 输出 1生成器表达式:
gen = (i*i for i in range(3))
print(next(gen)) # 0一种特殊的迭代器,通过函数中的 yield 语句创建,支持惰性计算。节省内存,适合处理大数据集。生成器在 yield 处暂停执行,下一次调用 next() 时从断点继续
def simple_generator():
yield 1
yield 2
yield 3
gen = simple_generator()
print(next(gen)) # 输出 1类型转换让不同类型之间的数据互操作更顺畅。Python 提供大量内置构造函数来执行显式转换,推荐在输入校验、序列加工等场景主动使用,避免隐式转换带来的歧义。
| 目标类型 | 常用函数 | 典型输入 | 说明 |
|---|---|---|---|
int | int(x) | "123", 45.6, True | 仅保留整数部分,可传入 base 指定进制 |
float | float(x) | "3.14", 1 | 支持科学计数法字符串 |
str | str(x) | 任意对象 | 调用对象的 __str__ 方法 |
bool | bool(x) | 任意对象 | 非零/非空为 True |
list/tuple/set | list(x) 等 | 可迭代对象 | 集合去重,序列保序 |
dict | dict(iterable) | 形如 [(k, v)] | 元素需是二元序列 |
📌 提示:布尔表达式中会发生少量隐式转换,如
if 3:会被视为True。为了可读性,仍建议显式调用转换函数。
int()int() 会尝试将输入转换为整数,字符串可通过 base 参数指定进制,浮点数会被截断而非四舍五入。
print(int("123")) # 123
print(int(45.67)) # 45(仅截断)
print(int(True)) # 1
print(int("1101", base=2)) # 13
# 非数字字符串会抛出 ValueError
# int("abc")float()float() 能接受整数、布尔以及表示数字的字符串(含科学计数法)。若字符串含非法字符同样会抛出 ValueError。
print(float("123.45")) # 123.45
print(float(45)) # 45.0
print(float(True)) # 1.0
print(float("1e-3")) # 0.001str()str() 返回对象的可读描述,常用于日志或 UI 展示。
print(str(123)) # "123"
print(str(3.14)) # "3.14"
print(str([1, 2, 3])) # "[1, 2, 3]"
print(str(True)) # "True"bool()bool() 根据"真值表"判断真假:False、None、任意数值 0、空序列/映射均为 False,其他情况为 True。
print(bool(0), bool(42)) # False True
print(bool(""), bool("hello")) # False True
print(bool([]), bool([1, 2, 3])) # False True序列和集合之间转换主要依赖可迭代协议。集合会自动去重,字典构造要求元素是可迭代的键值对。
nums = [1, 2, 2, 3]
print(set(nums)) # {1, 2, 3}
print(list({1, 2, 3})) # [1, 2, 3]
t = (1, 2, 3)
print(list(t), tuple(nums)) # [1, 2, 3] (1, 2, 2, 3)
dict_data = {"a": 1, "b": 2}
print(list(dict_data.keys())) # ['a', 'b']
print(list(dict_data.items())) # [('a', 1), ('b', 2)]
pairs = [("id", 1), ("name", "Alice")]
print(dict(pairs)) # {'id': 1, 'name': 'Alice'}
print(dict.fromkeys(["a", "b"], 0)) # {'a': 0, 'b': 0}print(complex(1, 2)) # (1+2j)
print(chr(65), ord("A")) # 'A' 65
text = "你好"
buf = text.encode("utf-8")
print(buf) # b'\xe4\xbd\xa0\xe5\xa5\xbd'
print(buf.decode("utf-8")) # 你好
import ast
print(ast.literal_eval("[1, 2, 3]")) # [1, 2, 3]# 整数转换
print("=== 整数转换 ===")
print(f"int('123') = {int('123')}") # 123
print(f"int(45.67) = {int(45.67)}") # 45(截断,非四舍五入)
print(f"int(True) = {int(True)}") # 1
print(f"int('ff', 16) = {int('ff', 16)}") # 255(十六进制)
# 浮点数转换
print("\n=== 浮点数转换 ===")
print(f"float('3.14') = {float('3.14')}") # 3.14
print(f"float(42) = {float(42)}") # 42.0
print(f"float('1e-3') = {float('1e-3')}") # 0.001
# 字符串转换
print("\n=== 字符串转换 ===")
print(f"str(123) = '{str(123)}'") # '123'
print(f"str([1,2,3]) = '{str([1,2,3])}'") # '[1, 2, 3]'
# 容器转换
print("\n=== 容器转换 ===")
lst = [1, 2, 2, 3]
print(f"set([1,2,2,3]) = {set(lst)}") # {1, 2, 3}(去重)
print(f"list((1,2,3)) = {list((1,2,3))}") # [1, 2, 3]
print(f"tuple([1,2,3]) = {tuple([1,2,3])}") # (1, 2, 3)
# 字典转换
print("\n=== 字典转换 ===")
pairs = [('a', 1), ('b', 2)]
print(f"dict([('a',1), ('b',2)]) = {dict(pairs)}") # {'a': 1, 'b': 2}int()、float() 等处理,避免隐式真值转换造成逻辑漏洞。try...except ValueError,确保程序稳健。decimal.Decimal 或 fractions.Fraction。list()、tuple() 等只会复制最外层引用,嵌套结构仍指向同一对象。set() 会打乱顺序,必要时再用 sorted()。eval(),一般推荐 ast.literal_eval()。| 方法 | 返回值 | 继承支持 | 推荐场景 | 性能 |
|---|---|---|---|---|
type(obj) | 类型对象 | 否 | 获取确切类型、元编程 | 最快 |
isinstance(obj, type) | bool | 是 | 类型检查、API 验证 | 快 |
obj.__class__ | 类型对象 | 否 | 访问类属性、动态创建 | 快 |
type(obj) is Type | bool | 否 | 精确匹配(排除子类) | 最快 |
# type() 返回对象的精确类型
print("=== type() 示例 ===")
x = 42
print(f"type(42) = {type(x)}") # <class 'int'>
print(f"type(42) == int: {type(x) == int}") # True
print(f"type(42) is int: {type(x) is int}") # True(推荐用 is)
# isinstance() 支持继承检查
print("\n=== isinstance() 示例 ===")
print(f"isinstance(42, int): {isinstance(x, int)}") # True
print(f"isinstance(42, object): {isinstance(x, object)}") # True(所有类型都继承 object)
print(f"isinstance(42, (int, float)): {isinstance(x, (int, float))}") # True(支持类型元组)
# bool 是 int 子类的特殊情况
print("\n=== bool 是 int 子类 ===")
b = True
print(f"type(True) == int: {type(b) == int}") # False(精确类型不同)
print(f"isinstance(True, int): {isinstance(b, int)}") # True(bool 继承自 int)
print(f"True + True = {True + True}") # 2(bool 可参与整数运算)
# 自定义类示例
print("\n=== 自定义类继承 ===")
class Animal: pass
class Dog(Animal): pass
dog = Dog()
print(f"type(dog) is Dog: {type(dog) is Dog}") # True
print(f"type(dog) is Animal: {type(dog) is Animal}") # False
print(f"isinstance(dog, Dog): {isinstance(dog, Dog)}") # True
print(f"isinstance(dog, Animal): {isinstance(dog, Animal)}") # True
# 何时使用 type() vs isinstance()
print("\n=== 使用场景建议 ===")
print("type(obj) is SomeClass → 精确匹配,排除子类")
print("isinstance(obj, Type) → 类型检查,支持继承")
print("isinstance(obj, (A, B)) → 多类型检查")type(obj) 返回对象的具体类型,但在继承体系中推荐 isinstance(obj, SomeType)typing 模块可为函数和变量添加类型提示,配合静态检查工具提升可维护性from typing import Iterable
def consume(xs: Iterable[int]) -> int:
return sum(xs)
import numbers
print(isinstance(3, numbers.Integral)) # True使用 sys.getsizeof() 查看对象的内存占用:
import sys
# 基本类型内存占用(64 位 CPython 3.14,版本间可能略有差异)
print("=== 基本类型内存占用 ===")
print(f"int(0): {sys.getsizeof(0)} 字节") # 28 字节
print(f"int(1): {sys.getsizeof(1)} 字节") # 28 字节
print(f"int(2**30): {sys.getsizeof(2**30)} 字节") # 32 字节
print(f"float(1.0): {sys.getsizeof(1.0)} 字节") # 24 字节
print(f"bool(True): {sys.getsizeof(True)} 字节") # 28 字节(继承 int)
print(f"None: {sys.getsizeof(None)} 字节") # 16 字节
# 字符串内存占用
print("\n=== 字符串内存占用 ===")
print(f"空字符串 '': {sys.getsizeof('')} 字节") # 41 字节
print(f"'a': {sys.getsizeof('a')} 字节") # 42 字节
print(f"'abc': {sys.getsizeof('abc')} 字节") # 44 字节
print(f"'你好': {sys.getsizeof('你好')} 字节") # 62 字节
# 容器内存占用(不含元素)
print("\n=== 容器内存占用(不含元素) ===")
print(f"空列表 []: {sys.getsizeof([])} 字节") # 56 字节
print(f"[1,2,3]: {sys.getsizeof([1,2,3])} 字节") # 88 字节
print(f"空元组 (): {sys.getsizeof(())} 字节") # 48 字节
print(f"(1,2,3): {sys.getsizeof((1,2,3))} 字节") # 72 字节
print(f"空集合 set(): {sys.getsizeof(set())} 字节") # 216 字节
print(f"空字典 {{}}: {sys.getsizeof({})} 字节") # 64 字节
# 注意 - getsizeof 只计算对象本身
print("\n=== 注意事项 ===")
print("getsizeof() 只计算对象本身的内存")
print("对于容器,不包含元素占用的内存")
print("计算总内存需要递归统计所有元素")| 类型 | 精度 | 范围 | 适用场景 | 性能 |
|---|---|---|---|---|
int | 任意精度 | 仅受内存限制 | 计数、索引、大数运算 | 快 |
float | 53 位有效数字 | ±1.8e308 | 科学计算、近似值 | 最快(硬件加速) |
Decimal | 可配置(默认 28 位) | 可配置 | 金融、精确计算 | 慢 |
Fraction | 任意精度 | 仅受内存限制 | 分数运算、精确有理数 | 慢 |
from decimal import Decimal
from fractions import Fraction
# int - 任意精度整数
big_int = 10 ** 100 # 古戈尔,无溢出
# float - IEEE 754 双精度
approx_pi = 3.14159265358979
# Decimal - 精确十进制
exact_price = Decimal('19.99')
# Fraction - 精确分数
one_third = Fraction(1, 3) # 精确的 1/3
print(f"1/3 = {one_third}") # 1/3
print(f"float(1/3) = {float(one_third):.10f}") # 0.3333333333| 转换方式 | 安全性 | 可预测性 | 推荐度 |
|---|---|---|---|
显式转换 int(x) | 高 | 高 | 推荐 |
隐式真值转换 if x: | 中 | 中 | 谨慎使用 |
隐式数值提升 int + float | 高 | 高 | 安全 |
| 字符串隐式转换 | 低 | 低 | 避免 |
# 经典的浮点数精度问题
print("=== 浮点数精度陷阱 ===")
print(f"0.1 + 0.2 = {0.1 + 0.2}") # 0.30000000000000004
print(f"0.1 + 0.2 == 0.3: {0.1 + 0.2 == 0.3}") # False!
# 原因分析
print("\n原因:二进制无法精确表示某些十进制小数")
print(f"0.1 的二进制表示: {0.1:.20f}") # 0.10000000000000000555
print(f"0.2 的二进制表示: {0.2:.20f}") # 0.20000000000000001110
# 解决方案
print("\n=== 解决方案 ===")
from decimal import Decimal
print(f"Decimal('0.1') + Decimal('0.2') = {Decimal('0.1') + Decimal('0.2')}") # 0.3
# 比较浮点数的正确方法
print("\n=== 比较浮点数的正确方法 ===")
a, b = 0.1 + 0.2, 0.3
epsilon = 1e-10 # 容差
print(f"abs(a - b) < epsilon: {abs(a - b) < epsilon}") # True
# 使用 math.isclose(Python 3.5+)
import math
print(f"math.isclose(0.1 + 0.2, 0.3): {math.isclose(0.1 + 0.2, 0.3)}") # True# Python 缓存小整数 [-5, 256]
print("=== 小整数池陷阱 ===")
a = 256
b = 256
print(f"a = 256, b = 256")
print(f"a is b: {a is b}") # True(同一对象)
# 超出缓存范围
c = 257
d = 257
print(f"\nc = 257, d = 257")
print(f"c is d: {c is d}") # True(同一脚本中字面量常量被编译器合并;运行时分别创建才为 False)
# 字符串也有类似优化
print("\n=== 字符串驻留 ===")
s1 = "hello"
s2 = "hello"
print(f"'hello' is 'hello': {s1 is s2}") # True(字符串驻留)
# 包含特殊字符的字符串不在标识符驻留范围内(实现细节)
s3 = "hello!"
s4 = "hello!"
print(f"'hello!' is 'hello!': {s3 is s4}") # True(同一脚本中字面量被合并;交互式逐行执行可能 False)
# 最佳实践
print("\n=== 最佳实践 ===")
print("比较值用 ==,比较身份用 is")
print("is 仅用于 None、True、False、单例对象")
print("不要用 is 比较整数、字符串等基本类型")# bool 继承自 int 的陷阱
print("=== bool 是 int 子类的陷阱 ===")
print(f"True + True = {True + True}") # 2
print(f"True * 10 = {True * 10}") # 10
print(f"False * 100 = {False * 100}") # 0
print(f"sum([True, True, False]) = {sum([True, True, False])}") # 2
# 可能导致意外行为的场景
print("\n=== 潜在问题 ===")
values = [1, 2, 3, True, False]
print(f"sum([1, 2, 3, True, False]) = {sum(values)}") # 7(True=1, False=0)
# 类型检查的陷阱
print("\n=== 类型检查陷阱 ===")
x = True
print(f"isinstance(True, int): {isinstance(x, int)}") # True
print(f"type(True) == int: {type(x) == int}") # False
# 精确检查 bool
print("\n=== 精确检查 bool 的方法 ===")
def is_bool(value):
"""精确检查是否为 bool 类型(排除 int)"""
return type(value) is bool
print(f"is_bool(True): {is_bool(True)}") # True
print(f"is_bool(1): {is_bool(1)}") # False# None 的正确判断方式
print("=== None 判断的正确方式 ===")
x = None
# 推荐方式
print(f"x is None: {x is None}") # True(推荐)
print(f"x is not None: {x is not None}") # False(推荐)
# 不推荐方式
print(f"x == None: {x == None}") # True(不推荐)
print(f"not x: {not x}") # True(不推荐,可能误判其他假值)
# 为什么用 is 而非 ==
print("\n=== 为什么用 is 而非 == ===")
class MyClass:
def __eq__(self, other):
return True # 重写 __eq__,与任何值比较都返回 True
obj = MyClass()
print(f"obj == None: {obj == None}") # True(被 __eq__ 影响)
print(f"obj is None: {obj is None}") # False(精确判断)
# None 与其他假值的区别
print("\n=== None vs 其他假值 ===")
false_values = [None, False, 0, 0.0, "", [], {}, set()]
for val in false_values:
print(f"{repr(val):10} is None: {val is None:5} bool: {bool(val)}")# 可变默认参数陷阱(前面已提,这里补充更多细节)
print("=== 可变默认参数陷阱 ===")
# 问题代码
def add_item(item, my_list=[]):
"""错误:默认列表在函数定义时创建,所有调用共享"""
my_list.append(item)
return my_list
print(f"第一次调用: {add_item(1)}") # [1]
print(f"第二次调用: {add_item(2)}") # [1, 2](共享了同一个列表)
print(f"第三次调用: {add_item(3)}") # [1, 2, 3]
# 查看默认参数
print(f"\n函数的默认参数: {add_item.__defaults__}") # ([1, 2, 3],)
# 正确写法
def add_item_correct(item, my_list=None):
"""正确:使用 None 作为哨兵值"""
if my_list is None:
my_list = []
my_list.append(item)
return my_list
print(f"\n正确方式第一次: {add_item_correct(1)}") # [1]
print(f"正确方式第二次: {add_item_correct(2)}") # [2]A:
重要性:
0.1 + 0.2 != 0.3?A: 这是浮点数精度问题,由二进制表示法引起。如需精确计算,使用 decimal.Decimal:
from decimal import Decimal
Decimal('0.1') + Decimal('0.2') # 精确结果is 和 == 有什么区别?A:
== 比较值是否相等is 比较是否是同一个对象(内存地址相同)a = [1, 2]
b = [1, 2]
a == b # True,值相等
a is b # False,不是同一个对象A:
# 使用 type()
type(123) == int # True
# 使用 isinstance()(推荐,支持继承)
isinstance(123, int) # True
isinstance(123, (int, float)) # True,支持类型元组A:
int(3.7) # 3,截断小数部分
int(3.7 // 1) # 3,向下取整
float(3) # 3.0
round(3.5) # 4(Python 采用银行家舍入,.5 向偶数取整)A: None 是 Python 的特殊常量,表示"无值"或"缺失"。判断是否为 None 应使用 is None 而非 == None。
| 术语 | 英文 | 定义 |
|---|---|---|
| 强类型 | Strong Typing | 类型之间不会发生隐式转换(如 Python 不会自动将字符串转为数字) |
| 动态类型 | Dynamic Typing | 变量类型在运行时确定,无需预先声明(Python 是动态类型语言) |
| 静态类型 | Static Typing | 变量类型在编译时确定,需要预先声明(如 Java、C++) |
| 可变类型 | Mutable Type | 对象创建后可以修改其内容(如 list、dict、set) |
| 不可变类型 | Immutable Type | 对象创建后内容不可改变(如 int、str、tuple) |
| 鸭子类型 | Duck Typing | "如果它走起来像鸭子,叫起来像鸭子,那它就是鸭子"——关注对象的行为而非类型 |
| 类型推导 | Type Inference | 编译器或解释器自动推断表达式的类型 |
| 类型提示 | Type Hints | 为函数参数和返回值添加类型注解,供静态检查工具使用 |
| 真值测试 | Truthiness | 在布尔上下文中,非零、非空值为 True,反之为 False |
| 单例模式 | Singleton Pattern | 确保一个类只有一个实例(如 None、True、False) |
# 鸭子类型示例
print("=== 鸭子类型 ===")
class Duck:
def quack(self):
print("嘎嘎嘎")
class Person:
def quack(self):
print("我在学鸭子叫")
def make_it_quack(duck_like):
"""不关心参数类型,只关心是否有 quack 方法"""
duck_like.quack()
# 两种不同类型都可以工作
duck = Duck()
person = Person()
make_it_quack(duck) # 输出: 嘎嘎嘎
make_it_quack(person) # 输出: 我在学鸭子叫
# 类型检查 vs 鸭子类型
print("\n传统类型检查需要:")
print("if isinstance(obj, Duck): obj.quack()")
print("\n鸭子类型只需:")
print("obj.quack() # 只要有 quack 方法即可")| 特性 | 本文编写时 | Python 3.14 |
|---|---|---|
| 类型注解求值 | 运行时立即求值 | PEP 649/749 延迟求值:注解不再在定义时执行,解决前向引用,提升启动性能 |
| 字符串模板 | 普通 f-string / str.format | PEP 750 模板字符串 t"...":可插值且能被安全处理(3.14 新特性) |
| 标准库多解释器 | 无官方支持 | PEP 734:concurrent.interpreters 模块支持在同一进程创建多个子解释器 |
| 调试 | 仅 Python 内建 pdb / IDE 调试 | PEP 768:安全的 CPython 外部调试器接口(custom debugger protocol) |
| 字节码与运行时 | 3.12 前无 JIT | 3.13 引入实验性 JIT(PEP 744);3.14 进一步改进 free-threaded(无 GIL)构建 |
datetime API | utcnow() 常用 | 3.12 起弃用,官方要求改用 datetime.now(tz=datetime.UTC)(aware 对象) |
| 压缩算法 | zlib / gzip / bz2 / lzma | 3.14 新增标准库 Zstandard 支持(PEP 784) |
本文讲解的语法与数据结构原理在 3.14 中依然成立;新项目建议基于 Python 3.13/3.14,并优先使用 aware datetime、PEP 649 注解与最新类型语法。