# 关于类型
# import collections
- 除了 list、str 等基础数据类型,Python 还在 collections 这个标准库中,提供了一些额外的数据类型,用作存放数据的容器。
- 官方文档 (opens new window)
# abc
collections.abc
提供了一些抽象类(abstract class),常用于类型注释、类型检查。如果一个对象实现了内置方法
__next__()
,则属于迭代器(Iterator)。>>> from collections.abc import Iterator >>> isinstance('Hello', Iterator) False >>> isinstance(iter('Hello'), Iterator) True
如果一个对象实现了内置方法
__iter__()
,则属于可迭代对象(Iterable)。>>> from collections.abc import Iterable >>> isinstance('Hello', Iterable) True >>> isinstance(iter('Hello'), Iterable) True
如果一个对象实现了内置方法
__hash__()
,则属于可哈希对象(Hashable)。>>> from collections.abc import Hashable >>> isinstance(1, Hashable) True
# Counter
假设一个 list 包含一些重复的元素,如何统计每个元素的出现次数?
- 可以对于每个元素,调用一次
list.count(xx)
,统计该元素的出现次数。但这样比较麻烦,性能低。 - 可以基于 list 创建一个
collections.Counter
对象,自动统计每个元素的出现次数。
- 可以对于每个元素,调用一次
定义:
Counter(iterable=None, /, **kwargs)
- Counter 类是 dict 类的子类,因此兼容 dict 的大部分方法。
- 调用 Counter(iterable) 时,会将 iterable 对象中的每个元素,保存为字典中一个 key 。然后将每个元素的出现次数,保存为 key 对应的 value 。
例:统计每个字母的出现次数
>>> from collections import Counter >>> c = Counter('hello') >>> c Counter({'l': 2, 'h': 1, 'e': 1, 'o': 1}) >>> c['h'] # 查询某个元素的出现次数 1 >>> c['x'] # 如果查询的元素不存在,则返回 0 ,而不是抛出 KeyError 异常 0 >>> c['x'] = 1 # 可以修改元素的出现次数,像修改一个 dict 对象的 value >>> c.most_common(2) # 返回出现次数最多的 n 个元素 [('l', 2), ('h', 1)] >>> c.update('hi') # 统计更多元素的出现次数,累加到当前 Counter 。这相当于 c += Counter('hi') >>> c Counter({'h': 2, 'l': 2, 'e': 1, 'o': 1, 'i': 1})
两个 Counter 对象之间,支持以下运算符:
>>> c1 = Counter('aab') >>> c1 Counter({'a': 2, 'b': 1}) >>> c2 = Counter('abb') >>> c2 Counter({'b': 2, 'a': 1}) >>> c1 & c2 # 交集 Counter({'a': 1, 'b': 1}) >>> c1 | c2 # 并集 Counter({'a': 2, 'b': 2}) >>> c1 - c2 # 差集 Counter({'a': 1}) >>> c1 + c2 # 累加 Counter({'a': 3, 'b': 3})
# deque
list 类型没有长度限制,可以存放任意个元素。而 deque 类型,相当于一个限制了长度的 list 。
- deque 缩写自 double-end queue(双端队列)。
- deque 只能从左端或右端插入元素,不能从中间插入。因此时间复杂度为 O(1) ,性能高。
- deque 从某一端插入一个元素时,如果 deque 已达到最大长度,则会从另一端删除一个元素。
定义:
deque(iterable=[], maxlen=None)
- maxlen 默认值为 None ,表示不限制长度。
例:创建
>>> from collections import deque >>> deque() deque([]) >>> deque(maxlen=3) deque([], maxlen=3) >>> deque('hello', maxlen=3) deque(['l', 'l', 'o'], maxlen=3)
例:读取
>>> q = deque('hello', maxlen=3) >>> q[0] # 支持索引 'l' >>> q[:] # 不支持切片 TypeError: sequence index must be integer, not 'slice'
例:插入
>>> q = deque('hello', maxlen=3) >>> q.append(4) # 从右端插入元素 >>> q deque(['l', 'o', 4], maxlen=3) >>> q.appendleft(5) # 从左端插入元素 >>> q deque([5, 'l', 'o'], maxlen=3) >>> q.extend('hi') >>> q deque(['o', 'h', 'i'], maxlen=3) >>> q.extendleft('hi') >>> q deque(['i', 'h', 'o'], maxlen=3)
例:修改
>>> q = deque('hello', maxlen=3) >>> q deque(['l', 'l', 'o'], maxlen=3) >>> q.reverse() # 翻转列表,反向排序所有元素 >>> q deque(['o', 'l', 'l'], maxlen=3) >>> q.rotate(1) # 让所有元素向右移动 1 位,最右端的元素会插入左端 >>> q deque(['l', 'o', 'l'], maxlen=3) >>> q.rotate(-1) # 让所有元素向左移动 1 位 >>> q deque(['o', 'l', 'l'], maxlen=3)
例:删除
>>> q = deque('hello', maxlen=3) >>> q.pop() 'o' >>> q deque(['i', 'h'], maxlen=3) >>> q.popleft() 'i' >>> q deque(['h'], maxlen=3) >>> q.clear() >>> q deque([], maxlen=3)
# import typing
:Python 的标准库,定义了一些数据类型,常用于类型注释、类型检查。
# 原理
什么是类型注释?
- Python 变量本身是无类型的,但可以添加类型注释,供 IDE 等工具进行静态类型检查。如下:
>>> x: int = 1
- 这里所说的类型,可以是 str、list 等内置类,或其它任何 class 。
- 类型别名(Type Alias):指将一个类型赋值给一个变量。如下:
>>> T = int >>> x : T = 1
- Python 变量本身是无类型的,但可以添加类型注释,供 IDE 等工具进行静态类型检查。如下:
常见类型:
Any # 匹配所有类型 List Tuple # 元组。比如 Tuple[int, str] 表示取值为一个元组,包含两个指定类型的值。 Sequence # 序列 Set Dict Iterator Iterable
# Callable
:表示可调用的对象。
- 例:
>>> from typing import Callable >>> x : Callable # 表示变量 x 是一个可调用对象 >>> x : Callable[[int, int], str] # 表示变量 x 可调用,且形参列表为 [int, int] 类型,返回值为 str 类型
# Optional
:表示取值是可选的。可以不赋值,即相当于赋值 None 。
- 例:
from typing import Optional def foo(arg: Optional[int] = None): pass
# Union
:表示属于多种类型之一,称为联合类型。
- 定义 Union 类型时,
- 如果只包含一个类型,则只返回该类型。
>>> Union[int] <class 'int'>
- 如果包含了重复的类型,则会去除重复:
>>> Union[int, int] <class 'int'>
- 如果嵌套了 Union 类型,则自动合并为一层 Union 。
>>> Union[Union[int, str], float] typing.Union[int, str, float]
- 如果只包含一个类型,则只返回该类型。
- 比较两个 Union 类型时,不考虑参数的顺序。
>>> Union[int, str] == Union[str, int] True >>> Union[int, str, int] == Union[str, int] True
# Type
:type 的别名。
- 例:
>>> from typing import Type >>> x : Type
# TypeVar
:用于定义类型变量,表示一种类型。
- 例:
>>> from typing import TypeVar >>> A = TypeVar('A') # 定义一个类型变量 A ,可以赋值任意类型 >>> A ~A >>> B = TypeVar('B', int, str) # 定义一个类型变量 B ,只能赋值指定的类型 >>> x : B = 1
- TypeVar 变量可用作泛型的参数:
>>> from typing import Sequence, TypeVar >>> T = TypeVar('T') >>> x : Sequence # Sequence 是一个已定义的泛型 >>> x : Sequence[T] >>> x : Sequence[T, T] # Sequence 只支持声明一个参数 TypeError: Too many arguments for typing.Sequence; actual 2, expected 1
# Generic
:用作泛型类的抽象基类。
- 泛型类:表示一个任意类型的类,只声明了形参的类型、数量。
- Generic 类的定义:
class Generic: def __class_getitem__(cls, params): ... def __init_subclass__(cls, *args, **kwargs): ...
- 例:定义泛型类
>>> from typing import TypeVar, Generic >>> A = TypeVar('A') >>> B = TypeVar('B') >>> class Test(Generic): # 继承 Generic 时,必须声明参数 ... pass ... TypeError: Cannot inherit from plain Generic >>> class Test(Generic[A]): ... pass ... >>> class Test(Generic[A, A]): # 如果声明多个参数,则必须互不相同 ... pass ... TypeError: Parameters to Generic[...] must all be unique >>> class Test(Generic[A, B]): ... def __init__(self, x:A=None, y:B=None): ... pass ... >>> Test() # 创建泛型类的示例时,可以不声明参数,像普通类一样使用 <__main__.Test object at 0x7f21e0369ff0> >>> Test[A]() # 如果声明了参数,则会检查参数数量是否一致,否则抛出异常。但不会强制类型检查 File "/usr/local/lib/python3.10/typing.py", line 1316, in __class_getitem__ _check_generic(cls, params, len(cls.__parameters__)) TypeError: Too few arguments for <class '__main__.Test'>; actual 1, expected 2 >>> Test[int, int]() <__main__.Test object at 0x7f21e0368910> >>> Test[int, str](1, 2) # 不会强制类型检查 <__main__.Test object at 0x7f347beb5270>
# import string
:Python 的标准库,提供了一些常用的字符集合。
关于数字:
>>> import string >>> string.digits # 全部阿拉伯数字 '0123456789' >>> string.hexdigits # 全部十六进制数字 '0123456789abcdefABCDEF'
关于字母:
>>> string.ascii_letters # 全部 ASCII 字母 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' >>> string.ascii_lowercase # 全部小写字母 'abcdefghijklmnopqrstuvwxyz' >>> string.ascii_uppercase # 全部大写字母 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
空白字符:
>>> string.whitespace # 所有空白字符 ' \t\n\r\x0b\x0c'
\x0b
表示让光标垂直换行,等价于\v
。\x0c
表示让打印机换到下一张纸,等价于\f
。\b
表示让光标回退一格。\x20
表示一个空格。