Skip to content

Commit fe5111a

Browse files
committed
Update public notes
1 parent 1884791 commit fe5111a

File tree

1 file changed

+175
-0
lines changed

1 file changed

+175
-0
lines changed
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
---
2+
created: "2025-10-25"
3+
updated: "2025-10-25"
4+
---
5+
> *最讨厌 python 的动态类型和无声明。
6+
>
7+
> ——鸽子 2025/10/25*
8+
9+
[typing --- 对类型提示的支持 — Python 3.14.0 文档](https://docs.python.org/zh-cn/3/library/typing.html#)
10+
11+
所以要写多多标记变量 `type`,不然在大项目不知道类型就要吃亏。
12+
- 没有类型提示
13+
- 写错也没提示
14+
- 看不懂别人代码
15+
16+
需要知道的是 `typing hinting` 本质上还是 **标注**,所以并不是真的会强制进行类型检查,比如说下面的代码实际上可以运行。
17+
18+
```python
19+
20+
def get_text():
21+
a: str = 1 # 虽然标记为 str,但是实际上是 int
22+
return a
23+
24+
string = get_text() # 调用代码的时候 IDE 类型推导 string 也应该是 str 类型,然鹅实际上是 int
25+
```
26+
27+
乱标记后面报错就老实了。
28+
29+
> [!WARNING]
30+
> 本文大写的类型标注都来自于 `typing` 模块。小写的类型是已经内置的类型。
31+
>
32+
> 此外 `T` 代表可以用其他类型替代。
33+
34+
## No Pain
35+
36+
常见的基本类型就 `float` `int` `str` 之类这种。`class` 定义的类型也可以是类型的一种。
37+
38+
```python
39+
a: str = 'abs'
40+
41+
def sum(a: int, b: int) -> int:
42+
return a + b;
43+
```
44+
45+
## Mild
46+
47+
稍微复杂点的是 `collections` 集合类型。比如说 `dict` `list` 等。
48+
49+
一般可以用 `[]` 来进行具体的类型指定,比如说 `dict[str, int]` 代表 key 为 str 类型,value 为 int 类型的字典。 *可以类比 C++ 的 <>*
50+
51+
```cpp
52+
a: list[str] = [1,2,3]
53+
b: dict[str, float] = {"apple": 0.75, "banana": 1.25}
54+
c: tuple[int, ...] = (1, 2, 3) // ... 意思就是后面的和前面的一样 tuple[int, int, int]
55+
d: set[int] = {101, 102, 103}
56+
```
57+
58+
## Moderate
59+
60+
### 集合类型
61+
62+
typing 模块有很多很好用的类型。
63+
64+
- `Option[T]`: 要么是 T 类型,要么是 None
65+
- `Union[T1, T2, ...]`: 类型是 `T1, T2, ...` 其中一个。上面的 `Option[T]` 等同 `Union[T, None]`
66+
- `Any`:任何类型,相当于不标注类型。(慎用)
67+
- `Callable[[T1, T2, ...], T3]`: 可调用的对象(例如函数),其中 `T1, T2, ...` 是参数列表,`T3` 是返回类型。
68+
- `Literal[v1, v2, ...]`: 只会是其中一个字面值。
69+
70+
### 类型别名
71+
72+
用 `type` 标注类型别名。
73+
74+
```python
75+
type Vector = list[float]
76+
77+
def scale(scalar: float, vector: Vector) -> Vector:
78+
return [scalar * num for num in vector]
79+
80+
# 通过类型检查;浮点数列表是合格的 Vector。
81+
new_vector = scale(2.0, [1.0, -4.2, 5.4])
82+
```
83+
84+
`type` 语句是 3.12 加的,如果要向下兼容可以用 `Vector = list[float]` 直接赋值。
85+
86+
### NewType
87+
88+
可以用 NewType 创建与原类型不同的类型。
89+
90+
```python
91+
from typing import NewType
92+
93+
UserId = NewType('UserId', int)
94+
some_id = UserId(524313)
95+
```
96+
97+
```python
98+
def get_user_name(user_id: UserId) -> str:
99+
...
100+
101+
# 通过类型检查
102+
user_a = get_user_name(UserId(42351))
103+
104+
# 未通过类型检查;整数不能作为 UserId
105+
user_b = get_user_name(-1)
106+
```
107+
108+
### TYPE_CHECKING
109+
110+
一个在类型检查时会被检查器当成 `True`
111+
112+
### 类对象类型
113+
114+
`type[T]` 表示 class T 的类型。(类型本身,而非实例)
115+
116+
## Severe
117+
118+
### 懒加载
119+
120+
在遇到定义同时需要类型注解的时候会产生先有鸡还是先有蛋的问题。
121+
122+
为此,使用 `from __future__ import annotations` 解决。在使用后,类型检查会推迟到文档定义完才进行。
123+
124+
### 为了类型提示而导致循环引用
125+
126+
本身只想导入模块来获取类型提示,但是两个模块互相需要类型的话,就会产生循环引用。
127+
128+
为此,可以用下面这个小巧思。
129+
130+
```python
131+
from __future__ import annotaions
132+
from typing import TYPE_CHECKING
133+
134+
if TYPE_CHECKING:
135+
from module_a import ClassA
136+
```
137+
138+
这样在实际运行时不会导入模块,而在类型检查时检查器会进行类型导入。
139+
140+
## Very Severe
141+
142+
### Generic 泛型
143+
144+
懒得写。
145+
146+
```python
147+
from __future__ import annotations
148+
149+
from collections.abc import Mapping
150+
from typing import Iterable, Protocol, TypeVar
151+
152+
T = TypeVar('T')
153+
154+
155+
class Addable[T](Protocol):
156+
def __add__(self: T, other: T) -> T: ...
157+
158+
159+
def sum[T: Addable](a: T, b: T) -> T:
160+
return a + b
161+
162+
163+
def print_iter(iterable: Iterable) -> None:
164+
for item in iterable:
165+
print(item)
166+
167+
168+
def print_map(mapping: Mapping) -> None:
169+
for key, value in mapping.items():
170+
print(key, value)
171+
```
172+
173+
## Worst Pain Possible
174+
175+
pass

0 commit comments

Comments
 (0)