Python 与 TypeScript 对照手册
把常见 TS/JS -> Python 的概念、语法、类型、方法、函数、工程习惯做成可对照、可回查的手册。
第一部分:学习路径
1. 环境与运行方式
1.1 运行 Python
概念定义
Python 既可以像 Node 一样直接执行脚本,也可以进入 REPL 交互环境一行一行试代码。
前端/TS 心智模型
python demo.py类似node demo.jspython进入交互环境,类似浏览器 Console 或nodeREPL
Python 写法
python --version
python
python app.py
TS 对照写法
node --version
node
node app.js
差异提醒
- Python 一般不需要先编译成 JS 再运行。
.py文件默认按解释执行,不像 TS 需要tsc或运行时工具链支持。
常见坑
- 系统里可能同时有
python和py启动器,Windows 下都很常见。 - 安装完 Python 要确认
pip和虚拟环境都可用。
最小示例
print("hello python") # hello python
console.log("hello typescript"); // hello typescript
1.2 脚本入口
概念定义
Python 模块既可以被导入,也可以被直接运行。if __name__ == "__main__": 用来区分这两种场景。
前端/TS 心智模型
它有点像 Node 里的 if (require.main === module),只是写法不同。
Python 写法
def main():
print("run app") # run app
if __name__ == "__main__":
main()
TS 对照写法
function main() {
console.log("run app"); // run app
}
if (require.main === module) {
main();
}
差异提醒
- Python 模块导入时会执行顶层代码,所以脚本入口判断很重要。
常见坑
- 把测试代码直接写在模块顶层,导致导入时自动执行。
2. 基础语法与语句块
2.1 缩进而不是花括号
概念定义
Python 用缩进表示代码块,不用 {}。
前端/TS 心智模型
可以把缩进理解成“语法的一部分”,不是单纯代码风格。
Python 写法
age = 20
if age >= 18:
print("adult") # adult
else:
print("minor") # 这个分支当前不会执行
TS 对照写法
const age = 20;
if (age >= 18) {
console.log("adult"); // adult
} else {
console.log("minor"); // 这个分支当前不会执行
}
差异提醒
- Python 里同级代码必须对齐。
- 冒号
:常用于开启一个代码块。
常见坑
- 混用 tab 和空格。
- 少缩进或多缩进会直接语法报错。
2.2 注释与文档字符串
概念定义
- 单行注释用
# - 多行说明通常用三引号字符串
"""...""",函数/类/模块顶部常作为文档字符串
Python 写法
# 这是单行注释
def add(a, b):
"""返回两个数之和。"""
return a + b
TS 对照写法
// 这是单行注释
/**
* 返回两个数之和
*/
function add(a: number, b: number) {
return a + b;
}
差异提醒
- Python 的三引号本质上是字符串,不是专用注释语法。
3. 变量、绑定与基础类型
3.1 变量绑定
概念定义
Python 没有 var / let / const。名字只是“绑定到某个对象”的引用。
前端/TS 心智模型
更像“所有变量声明都只有一种形式”,但“对象是否可变”与“变量名是否可重新赋值”不是同一个维度。
Python 写法
name = "Alice"
age = 18
age = 19
TS 对照写法
let name = "Alice";
let age = 18;
age = 19;
差异提醒
- Python 不靠
const表达常量约束。 - 约定俗成会把常量写成全大写,如
MAX_RETRY = 3,但语言层不阻止修改。
常见坑
- 误以为 Python 名字重新赋值和对象内部修改是同一种操作。
最小示例
items = [1, 2]
alias = items
items.append(3)
print(alias) # [1, 2, 3]
const items = [1, 2];
const alias = items;
items.push(3);
console.log(alias); // [1, 2, 3]
3.2 int、float、bool、str、None
整数与浮点数
count = 10
price = 19.9
total = count * price # 199.0
const count: number = 10;
const price: number = 19.9;
const total = count * price; // 199
差异点:
- TS/JS 的
number同时覆盖整数和浮点数。 - Python 则区分
int和float。
布尔值
is_admin = True # True
is_done = False # False
const isAdmin = true; // true
const isDone = false; // false
差异点:
- Python 布尔值首字母大写:
True/False
字符串
name = "Alice" # "Alice"
message = f"hello, {name}" # "hello, Alice"
multi = """
line1
line2
""" # 包含换行的多行字符串
const name = "Alice"; // "Alice"
const message = `hello, ${name}`; // "hello, Alice"
const multi = `
line1
line2
`; // 包含换行的多行字符串
差异点:
- Python 常用
f"..."做字符串插值。 - Python 三引号支持多行字符串。
空值 None
result = None
if result is None:
print("empty") # empty
let result: string | null = null;
if (result === null) {
console.log("empty"); // empty
}
差异点:
None更接近 JS 里的null。- 判断
None推荐用is None,不要用== None。
常见坑
if value:会把0、""、[]、{}、None都视为假值。
4. 容器类型
4.1 list 对照 Array
概念定义
list 是 Python 最常用的有序可变容器。
前端/TS 心智模型
它最接近 JS 的 Array,但并不是方法一一对应;很多能力来自内置函数和语法。
Python 写法
nums = [1, 2, 3]
nums.append(4) # [1, 2, 3, 4]
nums.extend([5, 6]) # [1, 2, 3, 4, 5, 6]
first = nums[0] # 1
last = nums[-1] # 6
part = nums[1:3] # [2, 3]
TS 对照写法
const nums = [1, 2, 3];
nums.push(4); // [1, 2, 3, 4]
nums.push(...[5, 6]); // [1, 2, 3, 4, 5, 6]
const first = nums[0]; // 1
const last = nums[nums.length - 1]; // 6
const part = nums.slice(1, 3); // [2, 3]
常见方法对照
| Python | TS/JS 近似 | 说明 |
|---|---|---|
append(x) | push(x) | 末尾追加一个元素 |
extend(xs) | push(...xs) | 追加多个元素 |
insert(i, x) | splice(i, 0, x) | 在指定位置插入 |
pop() | pop() | 弹出末尾元素 |
remove(x) | splice(index, 1) | 按值删除第一个匹配项 |
sort() | sort() | 原地排序 |
reverse() | reverse() | 原地反转 |
count(x) | filter(...).length | 统计出现次数 |
index(x) | indexOf(x) | 查找位置 |
最小示例
users = ["a", "b", "c"]
users.remove("b")
print(users) # ['a', 'c']
const users = ["a", "b", "c"];
users.splice(users.indexOf("b"), 1);
console.log(users); // ["a", "c"]
4.2 tuple
概念定义
tuple 是有序不可变序列。
前端/TS 心智模型
最接近 TS 里的元组类型或只读定长数组。
Python 写法
point = (10, 20) # (10, 20)
x, y = point # x == 10, y == 20
TS 对照写法
const point: [number, number] = [10, 20]; // [10, 20]
const [x, y] = point; // x === 10, y === 20
差异提醒
- Python 元组更常用于“不可变的小结构”或“多返回值”。
4.3 dict 对照对象/Map
概念定义
dict 是键值映射。
前端/TS 心智模型
它有时像普通对象 {},有时又更接近 Map。不要把它简单当成 JS 对象的翻版。
Python 写法
user = {"name": "Alice", "age": 18}
name = user["name"] # "Alice"
age = user.get("age", 0) # 18
user["city"] = "Shanghai" # {"name": "Alice", "age": 18, "city": "Shanghai"}
TS 对照写法
const user = { name: "Alice", age: 18 };
const name = user.name; // "Alice"
const age = user.age ?? 0; // 18
Object.assign(user, { city: "Shanghai" }); // { name: "Alice", age: 18, city: "Shanghai" }
常见方法对照
| Python | TS/JS 近似 | 说明 |
|---|---|---|
d.keys() | Object.keys(obj) | 获取键 |
d.values() | Object.values(obj) | 获取值 |
d.items() | Object.entries(obj) | 获取键值对 |
d.get(k, default) | obj[k] ?? default | 安全取值 |
d.pop(k) | delete obj[k] 前先取值 | 删除并返回值 |
d.update(other) | Object.assign(obj, other) | 合并 |
差异提醒
- Python
dict的键不局限于字符串。 obj.key风格在 Python 字典里不成立,必须user["name"]或user.get("name")。
常见坑
- 直接取不存在的键会抛
KeyError。
4.4 set
概念定义
set 是无序不重复集合。
前端/TS 心智模型
几乎对应 JS 的 Set。
Python 写法
tags = {"python", "ts"}
tags.add("react") # {"python", "ts", "react"}
has_ts = "ts" in tags # True
TS 对照写法
const tags = new Set(["python", "ts"]);
tags.add("react"); // Set { "python", "ts", "react" }
const hasTs = tags.has("ts"); // true
常见操作
a = {1, 2, 3}
b = {3, 4, 5}
print(a | b) # {1, 2, 3, 4, 5},并集
print(a & b) # {3},交集
print(a - b) # {1, 2},差集
const a = new Set([1, 2, 3]);
const b = new Set([3, 4, 5]);
const union = new Set([...a, ...b]); // Set { 1, 2, 3, 4, 5 }
const intersection = new Set([...a].filter(v => b.has(v))); // Set { 3 }
const diff = new Set([...a].filter(v => !b.has(v))); // Set { 1, 2 }
5. 运算、比较与切片
5.1 比较与逻辑运算
age = 20
passed = age >= 18 and age < 60 # True
is_guest = not False # True
const age = 20;
const passed = age >= 18 && age < 60; // true
const isGuest = !false; // true
差异点:
- Python 用
and / or / not - TS/JS 用
&& / || / !
5.2 成员判断
nums = [1, 2, 3]
print(2 in nums) # True
print(5 not in nums) # True
const nums = [1, 2, 3];
console.log(nums.includes(2)); // true
console.log(!nums.includes(5)); // true
5.3 切片
text = "abcdef"
print(text[1:4]) # bcd;[1:4] 表示从下标 1 取到下标 4 前,不包含 4
print(text[:3]) # abc;[:3] 省略起始位置,表示从开头取到下标 3 前
print(text[::2]) # ace;[::2] 表示从头到尾每隔 2 个字符取 1 个
print(text[::-1]) # fedcba;[::-1] 表示倒序切片,常用来反转字符串或列表
const text = "abcdef";
console.log(text.slice(1, 4));
console.log(text.slice(0, 3));
console.log([...text].filter((_, i) => i % 2 === 0).join(""));
console.log([...text].reverse().join(""));
差异点:
- Python 切片适用于字符串、列表、元组。
[::-1]是非常常见的反转技巧。
6. 流程控制
6.1 if / elif / else
score = 88
if score >= 90:
level = "A"
elif score >= 80:
level = "B"
else:
level = "C"
# level == "B"
const score = 88;
let level = "";
if (score >= 90) {
level = "A";
} else if (score >= 80) {
level = "B";
} else {
level = "C";
}
// level === "B"
6.2 for 循环
概念定义
Python 的 for ... in ... 是遍历“可迭代对象”,不是 JS 里那种遍历对象键名的 for...in。
for item in [10, 20, 30]:
print(item)
for (const item of [10, 20, 30]) {
console.log(item);
}
差异提醒
- Python 的
for item in list更像 TS 的for...of - JS 的
for...in更像遍历对象键
6.3 range
for i in range(5):
print(i) # 依次输出 0、1、2、3、4;range(5) 会生成 0 到 4
for (let i = 0; i < 5; i++) {
console.log(i); // 依次输出 0、1、2、3、4;这里用 i++ 手动控制下标
}
6.4 while
count = 0
while count < 3:
print(count) # 依次输出 0、1、2
count += 1
let count = 0;
while (count < 3) {
console.log(count); // 依次输出 0、1、2
count += 1;
}
6.5 match
Python 3.10+ 有结构化模式匹配,类似更强的 switch。
status = 404
match status:
case 200:
text = "ok"
case 404:
text = "not found"
case _:
text = "unknown"
# text == "not found"
const status = 404;
let text = "";
switch (status) {
case 200:
text = "ok";
break;
case 404:
text = "not found";
break;
default:
text = "unknown";
}
// text === "not found"
7. 函数
7.1 基本函数定义
def add(a, b):
return a + b
function add(a: number, b: number) {
return a + b;
}
7.2 类型注解版函数
def add(a: int, b: int) -> int:
return a + b # 例如 add(1, 2) 返回 3
function add(a: number, b: number): number {
return a + b; // 例如 add(1, 2) 返回 3
}
7.3 默认参数
def greet(name: str, prefix: str = "Hello") -> str:
return f"{prefix}, {name}" # 例如 greet("Alice") 返回 "Hello, Alice"
function greet(name: string, prefix = "Hello"): string {
return `${prefix}, ${name}`; // 例如 greet("Alice") 返回 "Hello, Alice"
}
7.4 关键字参数
def create_user(name: str, age: int, city: str = "Shanghai"):
return {"name": name, "age": age, "city": city}
user = create_user(age=18, name="Alice") # {"name": "Alice", "age": 18, "city": "Shanghai"};关键字参数按参数名传值,所以顺序可以调整
function createUser({
name,
age,
city = "Shanghai",
}: {
name: string;
age: number;
city?: string;
}) {
return { name, age, city };
}
const user = createUser({ age: 18, name: "Alice" });
// { name: "Alice", age: 18, city: "Shanghai" }
差异点:
- Python 没有对象参数解构那种默认模式,关键字参数是另一套机制。
7.5 可变参数
def sum_all(*nums: int) -> int:
return sum(nums) # *nums 会把多个位置参数收集成 tuple;例如 sum_all(1, 2, 3) 返回 6
def print_profile(**kwargs):
print(kwargs) # **kwargs 会把多个具名参数收集成 dict;例如 print_profile(name="Alice", age=18) 会打印 {"name": "Alice", "age": 18}
function sumAll(...nums: number[]): number {
return nums.reduce((acc, n) => acc + n, 0); // ...nums 会把多个参数收集成数组;例如 sumAll(1, 2, 3) 返回 6
}
function printProfile(kwargs: Record<string, unknown>) {
console.log(kwargs); // 例如 { name: "Alice", age: 18 }
}
7.6 多返回值
def min_max(nums: list[int]) -> tuple[int, int]:
return min(nums), max(nums)
low, high = min_max([3, 1, 9]) # low == 1, high == 9
function minMax(nums: number[]): [number, number] {
return [Math.min(...nums), Math.max(...nums)];
}
const [low, high] = minMax([3, 1, 9]); // low === 1, high === 9
7.7 lambda
nums = [3, 1, 2]
sorted_nums = sorted(nums, key=lambda x: x) # [1, 2, 3];key= 指定排序依据,lambda x: x 表示按元素本身排序
const nums = [3, 1, 2];
const sortedNums = [...nums].sort((a, b) => a - b); // [1, 2, 3];a - b 这个比较函数表示按数值升序排序
差异点:
- Python 的
lambda只能写单表达式,不能写多行函数体。
7.8 作用域
count = 0
def inc():
global count
count += 1 # 调用一次后 count == 1;global count 表示这里修改的是外部同名变量
let count = 0;
function inc() {
count += 1; // 调用一次后 count === 1;这里默认就会修改外层作用域变量
}
差异点:
- Python 在函数里赋值会默认创建局部变量,想改外部变量要显式
global或nonlocal。
高频坑:默认可变参数
def append_item(item, bucket=[]):
bucket.append(item)
return bucket
print(append_item(1)) # [1]
print(append_item(2)) # [1, 2]
正确写法:
def append_item(item, bucket=None):
if bucket is None:
bucket = []
bucket.append(item)
return bucket
TS 对照:
function appendItem(item: number, bucket: number[] = []) {
bucket.push(item);
return bucket;
}
8. 常用语法糖
8.1 解包
point = (10, 20)
x, y = point # x == 10, y == 20;这是序列解包,右边会按顺序拆给左边变量
first, *rest = [1, 2, 3, 4] # first == 1, rest == [2, 3, 4];*rest 表示把剩余元素都收集起来
const point: [number, number] = [10, 20];
const [x, y] = point; // x === 10, y === 20;数组解构会按顺序拆值
const [first, ...rest] = [1, 2, 3, 4]; // first === 1, rest === [2, 3, 4];...rest 收集剩余元素
8.2 合并列表和字典
nums = [1, 2]
merged = [0, *nums, 3] # [0, 1, 2, 3];*nums 会把列表里的元素逐个展开
user = {"name": "Alice"}
full = {**user, "age": 18} # {"name": "Alice", "age": 18};**user 会把字典里的键值对展开后再合并
const nums = [1, 2];
const merged = [0, ...nums, 3]; // [0, 1, 2, 3];...nums 会把数组元素展开
const user = { name: "Alice" };
const full = { ...user, age: 18 }; // { name: "Alice", age: 18 };...user 会把对象属性展开
8.3 列表推导式
nums = [1, 2, 3, 4]
squares = [n * n for n in nums] # [1, 4, 9, 16];列表推导式会遍历 nums 并生成一个新列表
even_squares = [n * n for n in nums if n % 2 == 0] # [4, 16];if 条件表示先过滤偶数,再生成结果
const nums = [1, 2, 3, 4];
const squares = nums.map(n => n * n); // [1, 4, 9, 16]
const evenSquares = nums.filter(n => n % 2 === 0).map(n => n * n); // [4, 16]
8.4 字典推导式与集合推导式
nums = [1, 2, 3]
mapping = {n: n * n for n in nums} # {1: 1, 2: 4, 3: 9};字典推导式会生成键值映射
unique_lengths = {len(name) for name in ["a", "bb", "ccc", "bb"]} # {1, 2, 3};集合推导式会自动去重
const nums = [1, 2, 3];
const mapping = Object.fromEntries(nums.map(n => [n, n * n])); // { 1: 1, 2: 4, 3: 9 }
const uniqueLengths = new Set(["a", "bb", "ccc", "bb"].map(name => name.length)); // Set { 1, 2, 3 }
8.5 enumerate 和 zip
names = ["a", "b", "c"]
for index, name in enumerate(names):
print(index, name) # 依次输出 0 a、1 b、2 c;enumerate 会同时给出索引和值
for left, right in zip([1, 2], ["a", "b"]):
print(left, right) # 依次输出 1 a、2 b;zip 会按位置把多个序列一一配对
const names = ["a", "b", "c"];
names.forEach((name, index) => console.log(index, name)); // 依次输出 0 a、1 b、2 c;forEach 回调里可以同时拿到值和索引
[[1, "a"], [2, "b"]].forEach(([left, right]) => console.log(left, right)); // 依次输出 1 a、2 b;这里手动构造了配对后的二维数组
9. 字符串、列表、字典常用方法
9.1 字符串方法
text = " hello,Python "
print(text.strip()) # "hello,Python"
print(text.lower()) # " hello,python "
print(text.upper()) # " HELLO,PYTHON "
print(text.replace("Python", "TS")) # " hello,TS "
print(text.split(",")) # [" hello", "Python "]
print(",".join(["a", "b", "c"])) # "a,b,c"
print("python".startswith("py")) # True
print("python".endswith("on")) # True
const text = " hello,Python ";
console.log(text.trim()); // "hello,Python"
console.log(text.toLowerCase()); // " hello,python "
console.log(text.toUpperCase()); // " HELLO,PYTHON "
console.log(text.replace("Python", "TS")); // " hello,TS "
console.log(text.split(",")); // [" hello", "Python "]
console.log(["a", "b", "c"].join(",")); // "a,b,c"
console.log("python".startsWith("py")); // true
console.log("python".endsWith("on")); // true
9.2 列表方法
nums = [3, 1, 2]
nums.sort() # [1, 2, 3]
nums.reverse() # [3, 2, 1]
print(nums.count(1)) # 1
print(nums.index(3)) # 0
const nums = [3, 1, 2];
nums.sort((a, b) => a - b); // [1, 2, 3]
nums.reverse(); // [3, 2, 1]
console.log(nums.filter(n => n === 1).length); // 1
console.log(nums.indexOf(3)); // 0
9.3 字典方法
user = {"name": "Alice", "age": 18}
print(user.keys()) # dict_keys(["name", "age"])
print(user.values()) # dict_values(["Alice", 18])
print(user.items()) # dict_items([("name", "Alice"), ("age", 18)])
print(user.get("city", "unknown")) # "unknown"
user.update({"city": "Shanghai"}) # {"name": "Alice", "age": 18, "city": "Shanghai"}
const user = { name: "Alice", age: 18 };
console.log(Object.keys(user)); // ["name", "age"]
console.log(Object.values(user)); // ["Alice", 18]
console.log(Object.entries(user)); // [["name", "Alice"], ["age", 18]]
console.log(user["city" as keyof typeof user] ?? "unknown"); // "unknown"
Object.assign(user, { city: "Shanghai" }); // { name: "Alice", age: 18, city: "Shanghai" }
10. 模块、包与导入
10.1 导入模块
import math
from pathlib import Path
from utils import add
import path from "node:path";
import { add } from "./utils";
差异提醒
- Python 导入靠模块路径,不是文件扩展名。
- 一个目录里通常需要合理的包结构,尤其是多文件项目。
10.2 模块示例
utils.py
def add(a: int, b: int) -> int:
return a + b
main.py
from utils import add
print(add(1, 2)) # 3
TS 对照:
utils.ts
export function add(a: number, b: number) {
return a + b;
}
main.ts
import { add } from "./utils";
console.log(add(1, 2)); // 3
常见坑
- 直接在错误目录运行脚本,导致相对导入失败。
- 当前工作目录和模块搜索路径不是一回事。
11. 异常处理
11.1 try / except / finally
try:
value = int("123")
except ValueError as err:
print("convert failed", err) # 当前不会进入这个分支
else:
print("success", value) # success 123
finally:
print("done") # done
try {
const value = Number.parseInt("123", 10);
if (Number.isNaN(value)) {
throw new Error("convert failed");
}
console.log("success", value); // success 123
} catch (err) {
console.log("convert failed", err); // 当前不会进入这个分支
} finally {
console.log("done"); // done
}
差异提醒
- Python 有更明确的异常类型体系,常按具体异常类型捕获。
else块表示“没有异常时执行”。
11.2 主动抛错
def divide(a: float, b: float) -> float:
if b == 0:
raise ValueError("b cannot be 0")
return a / b
function divide(a: number, b: number): number {
if (b === 0) {
throw new Error("b cannot be 0");
}
return a / b;
}
12. 文件操作与上下文管理器
12.1 读写文件
with open("demo.txt", "w", encoding="utf-8") as f:
f.write("hello") # demo.txt 里会写入 hello
with open("demo.txt", "r", encoding="utf-8") as f:
content = f.read() # "hello"
import { promises as fs } from "node:fs";
await fs.writeFile("demo.txt", "hello", "utf-8"); // demo.txt 里会写入 hello
const content = await fs.readFile("demo.txt", "utf-8"); // "hello"
差异提醒
with会自动释放资源,很像try/finally的语法糖。
12.2 上下文管理器
class Timer:
def __enter__(self):
print("start") # start
return self
def __exit__(self, exc_type, exc, tb):
print("end") # end
with Timer():
print("running") # running
async function withTimer(fn: () => Promise<void> | void) {
console.log("start"); // start
try {
await fn();
} finally {
console.log("end"); // end
}
}
13. 类、对象与面向对象
13.1 基本类
class User:
def __init__(self, name: str, age: int):
self.name = name
self.age = age
def greet(self) -> str:
return f"Hi, I am {self.name}"
user = User("Alice", 18)
print(user.greet()) # Hi, I am Alice
class User {
constructor(public name: string, public age: number) {}
greet(): string {
return `Hi, I am ${this.name}`;
}
}
const user = new User("Alice", 18);
console.log(user.greet()); // Hi, I am Alice
差异提醒
- Python 实例方法第一个参数必须显式写
self。 - 构造函数叫
__init__。
13.2 继承
class Admin(User):
def greet(self) -> str:
return f"Admin: {self.name}" # 例如返回 "Admin: Alice"
class Admin extends User {
override greet(): string {
return `Admin: ${this.name}`; // 例如返回 "Admin: Alice"
}
}
13.3 dataclass
概念定义
dataclass 用于快速定义“主要存数据”的类,减少样板代码。
from dataclasses import dataclass
@dataclass
class Product:
name: str
price: float
product = Product("Keyboard", 99.9) # Product(name="Keyboard", price=99.9)
class Product {
constructor(public name: string, public price: number) {}
}
const product = new Product("Keyboard", 99.9); // Product { name: "Keyboard", price: 99.9 }
14. 迭代器与生成器
14.1 可迭代对象
Python 里很多对象都能用于 for 循环,只要它们实现迭代协议。
for ch in "abc":
print(ch) # 依次输出 a、b、c
for (const ch of "abc") {
console.log(ch); // 依次输出 a、b、c
}
14.2 生成器
def countdown(n: int):
while n > 0:
yield n # yield 会逐个产出值,函数因此变成生成器
n -= 1
for item in countdown(3):
print(item) # 依次输出 3、2、1;for 会逐个取出 yield 产出的值
function* countdown(n: number) {
while (n > 0) {
yield n; // yield 会逐个产出值,函数因此变成 generator
n -= 1;
}
}
for (const item of countdown(3)) {
console.log(item); // 依次输出 3、2、1;for...of 会逐个取出 generator 产出的值
}
差异提醒
- Python 生成器和 JS generator 很像,但 Python 在数据处理场景里更常见。
15. 装饰器
15.1 基本装饰器
概念定义
装饰器本质上是“接收函数并返回新函数的函数”。
def logger(fn):
def wrapper(*args, **kwargs):
print("before") # before
result = fn(*args, **kwargs)
print("after") # after
return result
return wrapper
@logger
def add(a, b):
return a + b # 调用 add(1, 2) 时最终返回 3
function logger<T extends (...args: any[]) => any>(fn: T) {
return (...args: Parameters<T>): ReturnType<T> => {
console.log("before"); // before
const result = fn(...args);
console.log("after"); // after
return result;
};
}
const add = logger((a: number, b: number) => a + b); // 调用 add(1, 2) 时最终返回 3
差异提醒
- Python 装饰器语法
@decorator非常常见。 - 前端里更常见的是高阶函数、高阶组件、middleware 思维。
16. 类型注解与 typing
16.1 常见类型注解
name: str = "Alice" # "Alice"
age: int = 18 # 18
scores: list[int] = [1, 2, 3] # [1, 2, 3]
user: dict[str, int] = {"age": 18} # {"age": 18}
const name: string = "Alice"; // "Alice"
const age: number = 18; // 18
const scores: number[] = [1, 2, 3]; // [1, 2, 3]
const user: Record<string, number> = { age: 18 }; // { age: 18 }
16.2 Optional / 联合类型
from typing import Optional
nickname: Optional[str] = None # None
let nickname: string | null = null; // null
16.3 TypedDict
from typing import TypedDict
class UserDict(TypedDict):
name: str
age: int
user: UserDict = {"name": "Alice", "age": 18} # {"name": "Alice", "age": 18}
type UserDict = {
name: string;
age: number;
};
const user: UserDict = { name: "Alice", age: 18 }; // { name: "Alice", age: 18 }
16.4 泛型
from typing import TypeVar
T = TypeVar("T")
def first(items: list[T]) -> T:
return items[0] # 例如 first([10, 20, 30]) 返回 10
function first<T>(items: T[]): T {
return items[0]; // 例如 first([10, 20, 30]) 返回 10
}
差异提醒
- Python 类型注解默认不在运行时强校验,它更多服务于编辑器、静态检查和团队可读性。
17. 异步编程
17.1 async / await
import asyncio
async def fetch_data():
await asyncio.sleep(1)
return {"ok": True} # {"ok": True}
async def main():
result = await fetch_data()
print(result) # {'ok': True}
asyncio.run(main())
async function fetchData() {
await new Promise(resolve => setTimeout(resolve, 1000));
return { ok: true }; // { ok: true }
}
async function main() {
const result = await fetchData();
console.log(result); // { ok: true }
}
main();
差异提醒
- Python
async常基于asyncio事件循环。 - 它和浏览器/Node 的 Promise 模型相似,但不是同一套 API。
17.2 并发任务
import asyncio
async def task(name: str, delay: int):
await asyncio.sleep(delay)
return name # 返回对应任务名
async def main():
result = await asyncio.gather(task("a", 1), task("b", 2)) # gather 会并发等待多个协程并把结果收集成列表
print(result) # ['a', 'b']
async function task(name: string, delay: number) {
await new Promise(resolve => setTimeout(resolve, delay * 1000));
return name; // 返回对应任务名
}
async function main() {
const result = await Promise.all([task("a", 1), task("b", 2)]); // Promise.all 会并发等待多个 Promise 并收集结果
console.log(result); // ["a", "b"]
}
常见坑
- 忘了
await - 把同步阻塞代码塞进
async函数里,以为自动变非阻塞
18. 常用标准库映射
| 场景 | Python | TS/JS / Node |
|---|---|---|
| 路径处理 | pathlib.Path | node:path |
| 文件读写 | open、pathlib | node:fs |
| JSON | json | JSON |
| 时间日期 | datetime | Date |
| 随机数 | random | Math.random() |
| 哈希 | hashlib | node:crypto |
| 命令行参数 | argparse | process.argv / commander |
| 正则 | re | RegExp |
| HTTP 请求 | urllib / httpx / requests | fetch / axios |
18.1 JSON
import json
data = {"name": "Alice", "age": 18}
text = json.dumps(data, ensure_ascii=False) # '{"name": "Alice", "age": 18}'
obj = json.loads(text) # {"name": "Alice", "age": 18}
const data = { name: "Alice", age: 18 };
const text = JSON.stringify(data); // '{"name":"Alice","age":18}'
const obj = JSON.parse(text); // { name: "Alice", age: 18 }
18.2 路径
from pathlib import Path
path = Path("data") / "users.json"
print(path.exists())
import path from "node:path";
import fs from "node:fs";
const filePath = path.join("data", "users.json");
console.log(fs.existsSync(filePath));
18.3 日期时间
from datetime import datetime
now = datetime.now()
print(now.strftime("%Y-%m-%d %H:%M:%S"))
const now = new Date();
console.log(now.toISOString());
19. 最小工程化
19.1 创建虚拟环境
python -m venv .venv
Windows 激活:
.venv\Scripts\activate
macOS / Linux 激活:
source .venv/bin/activate
TS 对照心智:
- 类似给项目准备独立的
node_modules环境,只不过 Python 更强调解释器和依赖一起隔离。
19.2 安装依赖
pip install requests pytest ruff black
TS 对照:
npm install axios
npm install -D vitest eslint prettier typescript
19.3 推荐目录结构
project/
app/
__init__.py
main.py
utils.py
tests/
test_utils.py
requirements.txt
README.md
TS 对照:
project/
src/
main.ts
utils.ts
tests/
utils.test.ts
package.json
tsconfig.json
README.md
19.4 测试
tests/test_utils.py
from app.utils import add
def test_add():
assert add(1, 2) == 3
运行:
pytest
TS 对照:
import { describe, expect, it } from "vitest";
import { add } from "../src/utils";
describe("add", () => {
it("adds numbers", () => {
expect(add(1, 2)).toBe(3);
});
});
19.5 格式化与检查
ruff check .
black .
TS 对照:
eslint .
prettier --write .
19.6 调试
Python 常见方式:
print()- IDE 断点
pdb
import pdb
value = {"name": "Alice"}
pdb.set_trace()
print(value["name"])
TS 对照:
console.log()- 浏览器 DevTools / VS Code 断点
- Node inspector
第二部分:TypeScript -> Python 对照速查
20. 核心映射总表
| 前端/TS 概念 | Python 对应 | 备注 |
|---|---|---|
let | 直接赋值 x = ... | 无声明关键字 |
const | 约定常量全大写 | 无真正只读变量 |
null | None | 推荐 is None |
Array | list | 有序可变 |
| 元组类型 | tuple | 不可变序列 |
| 普通对象 | dict | 键值映射,不等于 JS 对象 |
Set | set | 无序去重 |
for...of | for x in xs | 遍历可迭代对象 |
for...in | 常用 for key in dict | 语义不同 |
| 模板字符串 | f"..." | 插值很常用 |
| 解构 | 解包 | a, b = pair |
| 展开运算符 | * / ** | 序列与字典分开 |
| 箭头函数 | lambda | 仅单表达式 |
Promise.all | asyncio.gather | 都用于并发等待 |
try/catch | try/except | 异常类型更细 |
class | class | 方法首参显式 self |
| Node 模块 | Python 模块/包 | 导入规则不同 |
21. 常见一眼就容易写错的点
21.1 真值判断
if not items:
print("empty")
if (!items.length) {
console.log("empty");
}
说明:
- Python 里空列表、空字典、空字符串、
0、None都是假值。
21.2 判断空值
if user is None:
print("no user")
if (user === null) {
console.log("no user");
}
21.3 深浅拷贝
import copy
state = {"items": [1, 2]}
shallow = state.copy() # 浅拷贝,内部列表仍可能共享引用
deep = copy.deepcopy(state) # 深拷贝,内部列表也会被复制
const state = { items: [1, 2] };
const shallow = { ...state }; // 浅拷贝,内部数组仍可能共享引用
const deep = structuredClone(state); // 深拷贝,内部数组也会被复制
21.4 排序
users = [{"age": 20}, {"age": 18}]
sorted_users = sorted(users, key=lambda x: x["age"]) # [{"age": 18}, {"age": 20}]
const users = [{ age: 20 }, { age: 18 }];
const sortedUsers = [...users].sort((a, b) => a.age - b.age); // [{ age: 18 }, { age: 20 }]
21.5 安全取值
city = user.get("city", "unknown") # 如果 city 不存在,则为 "unknown"
const city = user.city ?? "unknown"; // 如果 user.city 是 null/undefined,则为 "unknown"
22. 从前端思维切到 Python 的建议
- 不要先找“完全一模一样的语法”,先找“这段逻辑在 Python 里最自然的写法”。
- Python 很多时候更偏向内置能力和标准库,而不是链式 API。
- 多使用列表推导式、
enumerate、zip、pathlib、dataclass这些 Python 风格工具。 - 写 Python 时别太执着“所有东西都对象点点点调用”;很多能力来自语句和内置函数。
- 工程化上优先掌握
venv、pip、pytest、ruff/black,这几样已经足够开始做小项目。
23. 一个完整的最小示例
Python 版本
from dataclasses import dataclass
@dataclass
class Todo:
title: str
done: bool = False
def finish(todo: Todo) -> Todo:
return Todo(title=todo.title, done=True)
def main():
todos = [Todo("learn python"), Todo("write script")]
done_titles = [finish(todo).title for todo in todos if not todo.done]
print(done_titles)
if __name__ == "__main__":
main()
TypeScript 版本
type Todo = {
title: string;
done?: boolean;
};
function finish(todo: Todo): Todo {
return { ...todo, done: true };
}
function main() {
const todos: Todo[] = [{ title: "learn python" }, { title: "write script" }];
const doneTitles = todos.filter(todo => !todo.done).map(todo => finish(todo).title);
console.log(doneTitles);
}
main();
24. 记忆口诀
list像数组,但更依赖推导式和内置函数。dict像对象,但别把它当成对象字面量的完全复制。for x in xs像for...of,不是 JS 的for...in。None像null,判断时优先is None。- Python 没有
const,名字绑定和对象可变性要分开理解。 asyncio像 Promise 世界,但 API 体系是 Python 自己的。
评论区