2025-10-08 Python 标准库 9——内置类型:其他
文章目录
- 1. 上下文管理器类型
- 1.1. 上下文管理器的核心协议
- 1.1.1. `__enter__()`
- 1.1.2. `__exit__(exc_type, exc_val, exc_tb)`
- 1.3. `contextlib.contextmanager` 装饰器
- 1.4. 常见内置上下文管理器
- 2. 类型注解:Generic Alias 与 Union
- 2.1. Generic Alias(泛型别名)
- 2.2. Union(联合类型)
- 3. 其他内置类型
- 3.1. 模块(Module)
- 3.2. 函数(Function)
- 3.3. 方法(Method)
- 3.4. 特殊对象
- 3.4.1. 空对象(None)
- 3.4.2. 省略符(Ellipsis,`...`)
- 3.4.3. 未实现对象(NotImplemented)
- 4. 整数字符串转换长度限制(Python 3.11+)
- 4.1. 限制范围
- 4.2. 配置限制的方式
- 4.3. 注意事项
- 5. 总结
参考文档:内置类型 — Python 3.13.8 文档
1. 上下文管理器类型
在 Python 中,上下文管理器是支持 with
语句的核心机制,用于定义代码块的“运行时上下文”——即代码块执行前的初始化操作(如打开文件、获取锁)和执行后的清理操作(如关闭文件、释放锁),无需手动管理资源,避免遗漏清理步骤导致的问题(如文件句柄泄漏)。
1.1. 上下文管理器的核心协议
一个对象要成为上下文管理器,必须实现 __enter__()
和 __exit__()
两个特殊方法,这两个方法共同定义了 with
语句的执行逻辑。
1.1.1. __enter__()
- 作用:进入上下文时执行(
with
语句块执行前),负责初始化资源(如打开文件、创建连接)。 - 返回值:会绑定到
with
语句的as
子句变量(若指定),通常返回上下文管理器自身或关联资源(如文件对象)。 - 示例场景:文件对象的
__enter__()
返回自身,因此with open('file.txt') as f
中f
就是文件对象。
1.1.2. __exit__(exc_type, exc_val, exc_tb)
- 作用:退出上下文时执行(
with
语句块执行后,无论是否发生异常),负责清理资源(如关闭文件、释放锁)。 - 参数说明:
exc_type
:若语句块执行时发生异常,为异常类型(如ValueError
);否则为None
。exc_val
:若发生异常,为异常实例;否则为None
。exc_tb
:若发生异常,为异常的回溯对象(traceback
);否则为None
。
- 返回值:布尔值,
True
表示屏蔽语句块中发生的异常(不向外传播),False
表示不屏蔽(异常继续传播)。注意:不建议显式重新抛出异常,通过返回值控制即可。
通过自定义类实现 __enter__()
和 __exit__()
,可创建符合业务需求的上下文管理器。以下示例实现一个“文件读写上下文管理器”,自动处理文件打开与关闭:
class FileManager:def __init__(self, file_path, mode='r'):"""初始化:接收文件路径和打开模式"""self.file_path = file_pathself.mode = modeself.file = None # 初始化文件对象为Nonedef __enter__(self):"""进入上下文:打开文件并返回文件对象"""print(f"打开文件:{self.file_path}")self.file = open(self.file_path, self.mode, encoding='utf-8')return self.file # 绑定到as子句变量def __exit__(self, exc_type, exc_val, exc_tb):"""退出上下文:关闭文件,处理异常"""if self.file: # 确保文件已打开print(f"关闭文件:{self.file_path}")self.file.close()# 处理异常(示例:打印异常信息但不屏蔽)if exc_type is not None:print(f"执行异常:{exc_type.__name__}: {exc_val}")return False # 不屏蔽异常,让异常向外传播# 使用自定义上下文管理器
try:with FileManager('test.txt', 'w') as f:f.write("Hello, 上下文管理器!")# 故意触发异常(测试__exit__是否执行)raise ValueError("测试异常传播")
except ValueError as e:print(f"捕获外部异常:{e}")# 输出结果:
# 打开文件:test.txt
# 关闭文件:test.txt
# 执行异常:ValueError: 测试异常传播
# 捕获外部异常:测试异常传播
关键结论:即使 with
语句块中发生异常,__exit__()
仍会执行(确保文件关闭),体现了上下文管理器的“资源安全管理”核心价值。
1.3. contextlib.contextmanager
装饰器
手动实现 __enter__()
和 __exit__()
略显繁琐,Python 提供 contextlib.contextmanager
装饰器,可通过生成器函数快速创建上下文管理器,无需定义类。
其原理是:
- 生成器函数中,
yield
之前的代码对应__enter__()
的逻辑(初始化资源); yield
的返回值对应__enter__()
的返回值(绑定到as
子句);yield
之后的代码对应__exit__()
的逻辑(清理资源)。
示例:用装饰器实现“计时上下文管理器”
from contextlib import contextmanager
import time@contextmanager
def timer(name="操作"):"""计时上下文管理器:统计代码块执行时间"""# 1. 进入上下文:记录开始时间(对应__enter__)start_time = time.time()print(f"[{name}] 开始执行...")# 2. yield:返回开始时间(绑定到as子句),暂停等待代码块执行yield start_time# 3. 退出上下文:计算并打印耗时(对应__exit__)end_time = time.time()print(f"[{name}] 执行完成,耗时:{end_time - start_time:.4f}秒")# 使用计时上下文管理器
with timer("循环计算") as start:# 模拟耗时操作total = 0for i in range(1_000_000):total += i# 输出结果:
# [循环计算] 开始执行...
# [循环计算] 执行完成,耗时:0.0456秒
优势:代码更简洁,无需手动处理异常(装饰器会自动捕获异常并确保 yield
后的清理代码执行)。
1.4. 常见内置上下文管理器
Python 内置了多个实用的上下文管理器,无需自定义即可直接使用:
- 文件对象:
with open('file.txt') as f
,自动关闭文件; - 线程锁:
with threading.Lock()
,自动获取和释放锁; - decimal 上下文:
with decimal.localcontext()
,临时修改十进制计算上下文; suppress
上下文:with contextlib.suppress(ValueError)
,屏蔽指定异常(避免try-except
)。
示例:使用 suppress
屏蔽异常
from contextlib import suppress# 屏蔽ValueError,无需try-except
with suppress(ValueError):int("abc") # 转换失败,抛出ValueError,但被suppress屏蔽
print("程序继续执行(未崩溃)") # 正常输出
2. 类型注解:Generic Alias 与 Union
Python 3.9+ 引入了原生的类型注解类型,用于更简洁、直观地标注变量和函数的类型,替代早期 typing
模块中的 List[int]
、Union[int, str]
等写法。核心类型包括 Generic Alias
(泛型别名)和 Union
(联合类型)。
2.1. Generic Alias(泛型别名)
Generic Alias
是通过“类抽取”创建的泛型类型(如 list[int]
、dict[str, int]
),主要用于类型标注,明确容器类(如列表、字典)中元素的具体类型,帮助静态类型检查工具(如 mypy
)识别类型错误,提升代码可读性。
- 核心特点:
- 基于现有类创建(如
list
→list[int]
),需类实现__class_getitem__()
方法; - 仅用于类型标注,运行时不强制执行类型检查(Python 是动态类型语言);
- 支持嵌套(如
list[dict[str, int]]
表示“元素为字典的列表,字典的键是字符串、值是整数”)。
- 基于现有类创建(如
创建与使用示例
# 1. 标注列表类型:元素为float
def average(values: list[float]) -> float:"""计算列表中浮点数的平均值"""return sum(values) / len(values)# 2. 标注字典类型:键为str,值为list[int]
def count_words(sentences: list[str]) -> dict[str, int]:"""统计每个单词出现的次数"""word_count = {}for sent in sentences:for word in sent.split():word_count[word] = word_count.get(word, 0) + 1return word_count# 3. 嵌套泛型:list[dict[str, list[int]]]
def group_scores(students: list[dict[str, list[int]]]) -> dict[str, int]:"""按学生姓名分组,计算总分"""total_scores = {}for student in students:name = student["name"]scores = student["scores"]total_scores[name] = sum(scores)return total_scores# 测试(运行时不检查类型,仅标注)
scores = [{"name": "Alice", "scores": [85, 92]}, {"name": "Bob", "scores": [78, 88]}]
print(group_scores(scores)) # 输出:{'Alice': 177, 'Bob': 166}
关键属性:__origin__
与 __args__
Generic Alias
对象有两个只读属性,用于查看其原始类型和参数:
__origin__
:返回未带参数的原始类(如list[int].__origin__
→list
);__args__
:返回泛型参数的元组(如dict[str, int].__args__
→(str, int)
)。
# 查看泛型别名的属性
lst_type = list[int]
print(lst_type.__origin__) # 输出:<class 'list'>(原始类)
print(lst_type.__args__) # 输出:(int,)(泛型参数)dict_type = dict[str, list[float]]
print(dict_type.__origin__) # 输出:<class 'dict'>
print(dict_type.__args__) # 输出:(<class 'str'>, list[float])(嵌套参数)
注意事项
-
运行时类型擦除:
list[str]()
创建的对象类型仍是list
,而非list[str]
,泛型参数仅在标注阶段有效;t = list[str] l = t() print(type(l)) # 输出:<class 'list'>(类型擦除)
-
isinstance
不支持:不能用isinstance([1, 2], list[int])
检查,会抛出TypeError
;# 错误用法 # isinstance([1, 2], list[int]) # 报错:TypeError: isinstance() argument 2 cannot be a parameterized generic
Python 标准库中多个类支持泛型别名,常见的包括:
容器类 | 泛型别名示例 | 含义 |
---|---|---|
list | list[int] | 元素为整数的列表 |
dict | dict[str, bool] | 键为字符串、值为布尔的字典 |
set | set[bytes] | 元素为字节的集合 |
tuple | tuple[str, int] | 第一个元素为字符串、第二个为整数的元组 |
collections.deque | deque[float] | 元素为浮点数的双端队列 |
re.Match | re.Match[str] | 匹配结果为字符串的正则匹配对象 |
2.2. Union(联合类型)
Union
表示“多个类型中的任意一个”,使用 |
运算符创建(Python 3.10+ 支持),替代早期 typing.Union[int, str]
的写法,用于标注变量或参数可能为多种类型的场景(如“整数或浮点数”“字符串或 None”)。
- 核心特点:
- 自动平推与去重:
(int | str) | float
等价于int | str | float
,int | int | str
等价于int | str
; - 顺序无关:
int | str
与str | int
完全等价; - 与
Optional
兼容:str | None
等价于typing.Optional[str]
(表示“可选类型,可为 None”)。
- 自动平推与去重:
基础使用:标注多类型参数
# 1. 标注“整数或浮点数”类型的参数
def square(number: int | float) -> int | float:"""计算一个数的平方,支持整数或浮点数"""return number ** 2# 2. 标注“字符串或None”(等价于Optional[str])
def greet(name: str | None) -> str:"""根据姓名打招呼,name为None时使用默认值"""if name is None:name = "Guest"return f"Hello, {name}!"# 3. 嵌套Union:“列表或字典,元素为整数或字符串”
def process_data(data: list[int | str] | dict[str, int | str]) -> None:"""处理数据:支持列表或字典"""if isinstance(data, list):print("处理列表:", [str(x) for x in data])else:print("处理字典:", {k: str(v) for k, v in data.items()})# 测试
print(square(5)) # 输出:25(int)
print(square(3.2)) # 输出:10.24(float)
print(greet(None)) # 输出:Hello, Guest!
process_data([1, "a", 3]) # 输出:处理列表:['1', 'a', '3']
process_data({"a": 1, "b": "2"}) # 输出:处理字典:{'a': '1', 'b': '2'}
isinstance
支持
与 Generic Alias
不同,Union
支持 isinstance
和 issubclass
检查(但不支持包含 Generic Alias
的 Union
,如 int | list[int]
):
# 正确:检查变量是否为int或str
x = 123
print(isinstance(x, int | str)) # 输出:Truey = "abc"
print(isinstance(y, int | str)) # 输出:True# 错误:Union包含Generic Alias(list[int]),不支持isinstance
# z = [1, 2]
# print(isinstance(z, int | list[int])) # 报错:TypeError: isinstance() argument 2 cannot be a parameterized generic
与 typing.Union
的兼容性
|
运算符创建的 Union
与 typing.Union
完全等价,可混合使用:
from typing import Union# 两种写法等价
print(int | str == Union[int, str]) # 输出:True
print(str | None == Union[str, None])# 输出:True(等价于Optional[str])
3. 其他内置类型
Python 解释器还支持多种特殊内置类型,这些类型通常仅支持有限操作,用于特定场景(如模块、函数、方法、代码对象等)。
3.1. 模块(Module)
-
概念:模块是 Python 代码的组织单元,一个
.py
文件就是一个模块,用于封装变量、函数、类等。 -
核心操作:
- 属性访问:
module.name
(如sys.path
、os.path
); - 动态修改:通过
module.__dict__
访问模块的符号表(不建议直接修改)。
import sys# 访问模块属性 print(sys.version) # 输出:Python版本(如3.11.4 (main, Jun 12 2023, 15:19:37) [GCC 11.2.0]) print(sys.path) # 输出:模块搜索路径列表# 查看模块符号表(__dict__) print("sys模块中的前5个符号:", list(sys.__dict__.keys())[:5]) # 输出:sys模块中的前5个符号:['__name__', '__doc__', '__package__', '__loader__', '__spec__']
- 属性访问:
3.2. 函数(Function)
-
概念:通过
def
定义的可调用对象,支持参数传递和返回值。 -
分类:
- 用户自定义函数:
def func(): ...
; - 内置函数:
print()
、len()
等(由 C 实现,效率更高)。
- 用户自定义函数:
-
核心操作:仅支持调用(
func(args)
),可通过__name__
、__doc__
等属性查看函数信息。# 自定义函数 def add(a: int, b: int) -> int:"""计算两个整数的和"""return a + b# 查看函数属性 print(add.__name__) # 输出:add(函数名) print(add.__doc__) # 输出:计算两个整数的和(文档字符串) print(add(2, 3)) # 输出:5(函数调用)# 内置函数 print(len([1, 2, 3])) # 输出:3(内置函数调用)
3.3. 方法(Method)
-
概念:绑定到类或实例的函数,分为实例方法、类方法、静态方法。
-
关键特性:
- 实例方法:第一个参数为
self
,绑定到实例(如list.append()
); - 类方法:用
@classmethod
装饰,第一个参数为cls
,绑定到类; - 静态方法:用
@staticmethod
装饰,不绑定到类或实例,无默认参数。
class MyClass:count = 0 # 类属性def __init__(self, name: str):self.name = name # 实例属性MyClass.count += 1# 实例方法:绑定到实例def get_name(self) -> str:return self.name# 类方法:绑定到类@classmethoddef get_count(cls) -> int:return cls.count# 静态方法:不绑定@staticmethoddef add(a: int, b: int) -> int:return a + b# 实例方法调用(绑定到实例) obj = MyClass("Alice") print(obj.get_name()) # 输出:Alice(自动传入self)# 类方法调用(绑定到类) print(MyClass.get_count()) # 输出:1(自动传入cls)# 静态方法调用(无绑定) print(MyClass.add(2, 3)) # 输出:5(无需传入self/cls)
- 实例方法:第一个参数为
3.4. 特殊对象
3.4.1. 空对象(None)
-
概念:表示“无值”的单例对象,仅一个实例(
None
),用于表示函数无返回值、变量未赋值等。 -
特性:
- 类型为
NoneType
,type(None)
可获取类型; - 仅支持
is
/is not
比较(不建议用==
)。
# 函数无返回值,默认返回None def func():print("无返回值")result = func() print(result is None) # 输出:True# 变量未赋值时用None初始化 name: str | None = None if name is None:name = "Bob" print(name) # 输出:Bob
- 类型为
3.4.2. 省略符(Ellipsis,...
)
-
概念:表示“省略内容”的单例对象,写法为
Ellipsis
或...
。 -
常见用途:
- 类型标注:如
tuple[int, ...]
表示“元素为整数的变长元组”; - NumPy 切片:如
arr[..., 0]
表示“所有维度的第 0 列”; - 替代
pass
:作为空代码块的占位符。
# 1. 类型标注:变长元组 def sum_tuple(numbers: tuple[int, ...]) -> int:return sum(numbers)print(sum_tuple((1, 2, 3))) # 输出:6 print(sum_tuple((4,))) # 输出:4# 2. 替代pass class EmptyClass:... # 等价于pass# 3. NumPy切片(需安装numpy) # import numpy as np # arr = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) # print(arr[..., 0]) # 输出:[[1 3], [5 7]]
- 类型标注:如
3.4.3. 未实现对象(NotImplemented)
-
概念:表示“操作未实现”的单例对象,用于运算符重载时告知解释器“该操作需由其他对象处理”。
-
示例:在类中重载
__add__
,未支持的类型返回NotImplemented
:class MyNumber:def __init__(self, value: int):self.value = value# 重载加法运算符def __add__(self, other):if isinstance(other, MyNumber):return MyNumber(self.value + other.value)# 不支持的类型,返回NotImplemented,让解释器尝试other.__radd__(self)return NotImplementeddef __repr__(self):return f"MyNumber({self.value})"# 支持的类型:MyNumber + MyNumber a = MyNumber(2) b = MyNumber(3) print(a + b) # 输出:MyNumber(5)# 不支持的类型:MyNumber + int(返回NotImplemented,最终抛TypeError) try:print(a + 5) except TypeError as e:print(e) # 输出:unsupported operand type(s) for +: 'MyNumber' and 'int'
4. 整数字符串转换长度限制(Python 3.11+)
Python 3.11 引入了整数字符串转换长度限制,用于缓解“超长数字字符串转换导致的拒绝服务(DoS)攻击”——例如转换 '1' * 1_000_000
这类超长字符串会消耗大量 CPU 资源,限制可避免此类问题。
4.1. 限制范围
- 作用场景:仅对非 2 的幂次基数的转换生效(如十进制
int('123')
),对 2、4、8、16、32 等基数的转换无限制(算法为线性,效率高)。 - 受影响的 API:
int(string)
(默认十进制);str(integer)
、repr(integer)
(十进制字符串转换);- 格式化字符串:
f"{integer}"
、"{}.format(integer)"
。
- 默认限制:4300 位数字(可通过
sys.int_info.default_max_str_digits
查看),超过限制会抛出ValueError
。
import sys# 查看默认限制
print("默认整数字符串转换限制:", sys.int_info.default_max_str_digits) # 输出:4300# 1. 触发限制:转换4301位的数字字符串
long_str = '2' * 4301
try:int(long_str)
except ValueError as e:print("触发限制错误:", e)# 输出:触发限制错误:Exceeds the limit (4300 digits) for integer string conversion: value has 4301 digits; use sys.set_int_max_str_digits() to increase the limit# 2. 调整限制:临时提高上限(需谨慎,避免DoS风险)
sys.set_int_max_str_digits(5000) # 设为5000位
print(int('2' * 4500)) # 成功转换,无报错# 3. 禁用限制(不推荐,仅在信任输入时使用)
# sys.set_int_max_str_digits(0) # 0表示禁用限制
4.2. 配置限制的方式
除了代码中用 sys.set_int_max_str_digits()
调整,还可通过以下方式配置:
- 环境变量:
PYTHONINTMAXSTRDIGITS=5000 python script.py
; - 命令行参数:
python -X int_max_str_digits=5000 script.py
; - 子解释器:子解释器有独立的限制,需单独配置。
4.3. 注意事项
- 最低限制:不可低于 640 位(
sys.int_info.str_digits_check_threshold
),低于会抛出ValueError
; - 绕过限制:若需处理超长数字,可使用十六进制(如
int('ff' * 1000, 16)
),因 16 是 2 的幂次,无限制; - 谨慎禁用:禁用限制(设为 0)仅适用于完全信任输入的场景,否则可能面临 DoS 风险。
5. 总结
- 上下文管理器:通过
__enter__()
/__exit__()
或contextlib
装饰器实现,核心是安全管理资源(如文件、锁),避免手动清理遗漏; - 类型注解类型:
Generic Alias
(如list[int]
)用于标注容器元素类型,Union
(如int | str
)用于标注多类型场景,提升代码可读性和静态检查能力; - 其他内置类型:模块、函数、方法等是 Python 代码组织的基础,
None
、...
、NotImplemented
等特殊对象用于特定场景,需理解其单例特性和使用限制; - 整数字符串限制:Python 3.11+ 新增的安全机制,需注意受影响的 API 和配置方式,避免超长输入导致性能问题。