第 2 章:Python 基础语法
本章将系统讲解 Python 的核心语法。每个知识点都会与 JavaScript 进行对比, 帮助你利用已有的前端知识快速建立 Python 的思维模型。掌握本章内容后,你将能独立编写大多数 Python 脚本。
2.1 变量与数据类型
Python 是动态类型语言,与 JavaScript 类似,但语法更加简洁。最大的区别是: Python 不需要 let/const/var 关键字,直接赋值即可创建变量。
变量定义
# Python: 直接赋值,无需声明关键字
name = "Alice" # 字符串
age = 25 # 整数
height = 1.75 # 浮点数
is_student = True # 布尔值
# 可以同时给多个变量赋值(解构类似 JS)
x, y, z = 1, 2, 3
# 交换变量值(无需临时变量)
a, b = 10, 20
a, b = b, a # 现在 a=20, b=10
| 特性 | JavaScript | Python |
|---|---|---|
| 变量声明 | let x = 1; const y = 2; |
x = 1; y = 2(无关键字) |
| 常量 | const PI = 3.14 |
PI = 3.14(约定大写,但可修改) |
| 行尾分号 | 需要(可省略) | 不需要 |
| 变量交换 | [a, b] = [b, a] |
a, b = b, a |
基本数据类型
# 使用 type() 查看类型(类似 JS 的 typeof,但更精确)
print(type(42)) #
print(type(3.14)) #
print(type("hello")) #
print(type(True)) #
print(type(None)) # —— 类似 JS 的 null/undefined
# 类型转换
num_str = "100"
num = int(num_str) # 类似 parseInt()
price = float("19.99") # 类似 parseFloat()
text = str(42) # 类似 String(42)
Python 中只有 None 表示"空",没有 JavaScript 中 null 和 undefined 的区别。
函数没有显式 return 时,默认返回 None。判断是否为 None 使用 is 关键字:
if x is None:(而非 if x == None:)。
字符串操作
# 字符串定义:单引号、双引号、三引号都可以
name = 'Alice'
message = "Hello"
paragraph = """多行
字符串"""
# f-string 格式化(推荐,类似 JS 模板字符串)
age = 25
print(f"我叫 {name},今年 {age} 岁")
# 字符串方法(类似 JS String.prototype)
text = " Hello World "
print(text.strip()) # "Hello World" —— 类似 trim()
print(text.lower()) # " hello world " —— 类似 toLowerCase()
print(text.upper()) # " HELLO WORLD " —— 类似 toUpperCase()
print(text.replace("World", "Python")) # " Hello Python "
# 分割与连接
words = "a,b,c".split(",") # ['a', 'b', 'c'] —— 类似 split()
result = "-".join(words) # "a-b-c" —— JS 中需用 Array.prototype.join()
f-string 高级格式化
Python 的 f-string 远不止简单的变量插入。以下是一些前端开发中常用的高级技巧:
# 数字千分位(类似 JS 的 toLocaleString())
amount = 1234567.89
print(f"金额: {amount:,.2f}") # 金额: 1,234,567.89
# JS: amount.toLocaleString('en-US', { minimumFractionDigits: 2 })
# 百分比
ratio = 0.856
print(f"完成率: {ratio:.1%}") # 完成率: 85.6%
# 对齐与填充
name = "Python"
print(f"|{name:>15}|") # | Python| 右对齐
print(f"|{name:<15}|") # |Python | 左对齐
print(f"|{name:^15}|") # | Python | 居中
print(f"|{name:*^15}|") # |****Python*****| 用 * 填充
# 日期格式化
from datetime import datetime
now = datetime.now()
print(f"当前时间: {now:%Y-%m-%d %H:%M:%S}")
# 相当于 JS 的 dayjs().format('YYYY-MM-DD HH:mm:ss')
# 调用表达式(类似 JS 的 ${fn()})
def greet(name):
return f"Hello, {name}"
print(f"{greet('World')}") # Hello, World
# = 说明符(Python 3.8+):同时显示变量名和值(调试利器!)
x = 10
y = 20
print(f"{x + y = }") # x + y = 30
# 相当于 console.log({x}, {y}, x + y)
2.2 数据结构
Python 内置了四种核心数据结构,分别对应 JavaScript 中的不同概念。掌握它们是编写 Python 代码的基础。
列表 list —— 类似 JavaScript 的 Array
# 创建列表(类似 JS 数组)
fruits = ["apple", "banana", "cherry"]
mixed = [1, "two", 3.0, True] # 可以混合类型(但不推荐)
# 索引访问(与 JS 相同,从 0 开始)
print(fruits[0]) # "apple"
print(fruits[-1]) # "cherry" —— 负数索引从末尾开始,JS 中需用 at(-1)
# 切片操作(Python 特有,非常强大)
print(fruits[0:2]) # ["apple", "banana"] —— 索引 0 到 1(不含 2)
print(fruits[:2]) # ["apple", "banana"] —— 从头开始
print(fruits[1:]) # ["banana", "cherry"] —— 到末尾
print(fruits[::2]) # ["apple", "cherry"] —— 步长为 2
print(fruits[::-1]) # ["cherry", "banana", "apple"] —— 反转!
# 常用方法
fruits.append("orange") # 末尾添加,类似 push()
fruits.insert(1, "mango") # 指定位置插入,类似 splice()
fruits.remove("banana") # 删除第一个匹配项(JS 需用 filter 或 splice)
popped = fruits.pop() # 删除并返回末尾元素,类似 pop()
print(len(fruits)) # 获取长度,类似 .length
Python 的 [start:end:step] 切片是处理序列的利器。记住:
start 包含,end 不包含。省略即表示"从头"或"到尾"。
字典 dict —— 类似 JavaScript 的 Object / Map
# 创建字典(类似 JS 对象字面量)
user = {
"name": "Alice",
"age": 25,
"is_admin": False
}
# 访问值
print(user["name"]) # "Alice"
print(user.get("email")) # None —— 安全访问,不会报错
print(user.get("email", "default@example.com")) # 提供默认值
# 添加 / 修改
user["email"] = "alice@example.com"
user["age"] = 26
# 删除
del user["is_admin"] # 类似 delete user.isAdmin
# 遍历(类似 Object.entries())
for key, value in user.items():
print(f"{key}: {value}")
# 仅遍历键或值
for key in user.keys(): # 类似 Object.keys()
print(key)
for value in user.values(): # 类似 Object.values()
print(value)
- 字典的键可以是任意不可变类型(数字、字符串、元组),不限于字符串
- 字典没有属性访问语法(
user.name会报错),必须用user["name"] - 字典保持插入顺序(Python 3.7+),与 JS 对象相同
- 字典是独立的类型,不是 Object 的原型链体系
元组 tuple —— 不可变的列表
# 元组使用圆括号定义,创建后不可修改
point = (10, 20)
coordinates = (1, 2, 3)
# 单元素元组需要逗号!
single = (42,) # 注意逗号
not_tuple = (42) # 这只是整数 42
# 元组解包( unpacking,类似 JS 解构)
x, y = point
print(x, y) # 10 20
# 函数返回多个值时,实际返回的是元组
def get_min_max(numbers):
return min(numbers), max(numbers)
minimum, maximum = get_min_max([3, 1, 4, 1, 5])
print(minimum, maximum) # 1 5
当你有一组不应被修改的数据时,使用元组。元组比列表更轻量,且可作为字典的键(因为不可变)。 常见场景:坐标点、RGB 颜色值、数据库记录等。
集合 set —— 类似数学集合,去重利器
# 创建集合(自动去重,无序)
numbers = {1, 2, 3, 3, 3}
print(numbers) # {1, 2, 3}
# 从列表创建集合(快速去重)
items = ["a", "b", "a", "c", "b"]
unique = set(items)
print(unique) # {'a', 'b', 'c'}
# 集合运算(数学集合操作)
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
print(a | b) # {1, 2, 3, 4, 5, 6} —— 并集(类似 JS Set union)
print(a & b) # {3, 4} —— 交集
print(a - b) # {1, 2} —— 差集
print(a ^ b) # {1, 2, 5, 6} —— 对称差集
列表推导式 —— Python 的"语法糖"
列表推导式是 Python 最具特色的语法之一,用一行代码替代循环和 filter/map:
# 传统方式(类似 JS 的 for...of + push)
squares = []
for x in range(10):
squares.append(x ** 2)
# 列表推导式(一行搞定)
squares = [x ** 2 for x in range(10)]
# 带条件的列表推导式(类似 filter + map)
evens = [x for x in range(20) if x % 2 == 0]
# JS 对比:
// const evens = Array.from({length: 20}, (_, i) => i).filter(x => x % 2 === 0);
# 字典推导式
word_lengths = {word: len(word) for word in ["apple", "banana", "cherry"]}
# {'apple': 5, 'banana': 6, 'cherry': 6}
# 集合推导式
square_set = {x ** 2 for x in range(100)} # 自动去重
collections 模块 —— 高效数据结构
Python 的 collections 模块提供了 list/dict/tuple/set 之外的高级数据结构。
以下三种是最常用的,它们在性能和可读性上都优于手动实现的等价方案:
from collections import defaultdict, Counter, deque
# 1. defaultdict —— 带默认值的字典
# 不需要先检查 key 是否存在再初始化,类似 JS Map 的 getOrDefault
word_count = defaultdict(int)
sentence = "hello world hello python".split()
for word in sentence:
word_count[word] += 1 # 不存在时自动初始化为 0
print(dict(word_count)) # {'hello': 2, 'world': 1, 'python': 1}
# 按分类收集数据
users_by_role = defaultdict(list)
users = [("Alice", "admin"), ("Bob", "user"), ("Charlie", "admin")]
for name, role in users:
users_by_role[role].append(name)
print(dict(users_by_role))
# {'admin': ['Alice', 'Charlie'], 'user': ['Bob']}
# 2. Counter —— 计数器(统计频率的利器)
colors = ["red", "blue", "red", "green", "blue", "red"]
cnt = Counter(colors)
print(cnt) # Counter({'red': 3, 'blue': 2, 'green': 1})
print(cnt.most_common(2)) # [('red', 3), ('blue', 2)] —— 前 N 名
# 支持数学运算
cnt2 = Counter(["red", "green"])
print(cnt + cnt2) # Counter({'red': 4, 'blue': 2, 'green': 2})
print(cnt - cnt2) # Counter({'red': 2, 'blue': 2})
# 3. deque —— 双端队列(高性能的头部操作)
# list 在头部插入/删除是 O(n),deque 是 O(1)
history = deque(maxlen=5) # 最多保留 5 条记录
for i in range(10):
history.append(i)
print(history) # deque([5, 6, 7, 8, 9], maxlen=5)
# 灵活的双端操作
d = deque(["a", "b", "c"])
d.appendleft("x") # 左侧追加
d.append("y") # 右侧追加
print(d) # deque(['x', 'a', 'b', 'c', 'y'])
- defaultdict:取代
if key not in dict: dict[key] = []的重复代码 - Counter:统计词频、投票计数、排名榜等场景
- deque:队列、栈、滑动窗口、历史记录等场景
2.3 控制流
Python 的控制流结构与 JavaScript 类似,但语法更简洁。核心区别在于: 用缩进表示代码块,而非大括号。
条件语句 if/elif/else
score = 85
if score >= 90:
grade = "A"
elif score >= 80: # elif = else if,注意不是 "else if"
grade = "B"
elif score >= 70:
grade = "C"
else:
grade = "D"
print(f"成绩等级: {grade}")
# 三元表达式(类似 JS 的条件运算符)
status = "及格" if score >= 60 else "不及格"
# JS: const status = score >= 60 ? "及格" : "不及格";
Python 使用 4 个空格作为标准缩进(不要用 Tab)。缩进错误会导致 IndentationError。
建议配置编辑器将 Tab 自动转换为 4 个空格。
for 循环 —— 遍历而非索引
# Python 的 for 循环直接遍历元素(类似 JS 的 for...of)
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)
# 如果需要索引,使用 enumerate()(类似 JS 的 entries())
for index, fruit in enumerate(fruits):
print(f"{index}: {fruit}")
# 0: apple
# 1: banana
# 2: cherry
# 遍历字典
user = {"name": "Alice", "age": 25}
for key, value in user.items():
print(f"{key} = {value}")
# range() 生成数字序列(类似 JS 的 for (let i = 0; i < n; i++))
for i in range(5): # 0, 1, 2, 3, 4
print(i)
for i in range(2, 10, 2): # 2, 4, 6, 8(起始, 结束, 步长)
print(i)
while 循环与 break/continue
# while 循环(与 JS 语法相同)
count = 0
while count < 5:
print(count)
count += 1 # Python 没有 count++ 语法!
# break 和 continue(与 JS 完全相同)
for num in range(10):
if num == 3:
continue # 跳过当前迭代
if num == 7:
break # 终止循环
print(num)
# 输出: 0, 1, 2, 4, 5, 6
# else 子句(Python 特有!循环正常结束时执行)
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
break
else: # 注意缩进!没有触发 break 时执行
print(f"{n} 是质数")
# 输出: 2, 3, 5, 7 是质数
for...else 是 Python 的独特语法。当循环没有被 break 中断时,else 块会执行。
这在搜索场景中非常有用——如果找到目标就 break,否则执行 else 中的"未找到"逻辑。
2.4 函数
Python 使用 def 关键字定义函数。与 JavaScript 相比,Python 的函数参数系统更加灵活和强大。
基础函数定义
# 基础函数(类似 JS 的 function 声明)
def greet(name):
"""函数的文档字符串(docstring),说明函数用途"""
return f"Hello, {name}!"
print(greet("Alice")) # Hello, Alice!
# 多返回值(实际是返回元组)
def get_stats(numbers):
return min(numbers), max(numbers), sum(numbers) / len(numbers)
min_val, max_val, avg = get_stats([1, 2, 3, 4, 5])
print(min_val, max_val, avg) # 1 5 3.0
参数类型详解
# 1. 位置参数(默认方式)
def power(base, exponent):
return base ** exponent
print(power(2, 3)) # 8
# 2. 默认参数(类似 JS 的默认参数)
def greet(name, greeting="Hello"):
return f"{greeting}, {name}!"
print(greet("Alice")) # Hello, Alice!
print(greet("Bob", "Hi")) # Hi, Bob!
# ⚠️ 默认参数不要使用可变对象!
def bad_append(item, items=[]): # 错误!
items.append(item)
return items
def good_append(item, items=None): # 正确做法
if items is None:
items = []
items.append(item)
return items
# 3. *args —— 接收任意数量的位置参数(类似 JS 的 ...args)
def sum_all(*args):
return sum(args)
print(sum_all(1, 2, 3, 4)) # 10
# args 是一个元组: (1, 2, 3, 4)
# 4. **kwargs —— 接收任意数量的关键字参数(类似 JS 的对象解构剩余属性)
def create_user(**kwargs):
return {
"name": kwargs.get("name", "Anonymous"),
"age": kwargs.get("age", 0),
**kwargs # 展开其他属性
}
user = create_user(name="Alice", age=25, email="alice@example.com")
# 5. 组合使用(顺序: 位置参数, 默认参数, *args, **kwargs)
def func(a, b=2, *args, **kwargs):
print(f"a={a}, b={b}, args={args}, kwargs={kwargs}")
func(1, 3, 4, 5, x=10, y=20)
# a=1, b=3, args=(4, 5), kwargs={'x': 10, 'y': 20}
lambda 表达式
# lambda 语法(只能写单行表达式)
square = lambda x: x ** 2
print(square(5)) # 25
# 常用于排序和过滤(类似 JS 的箭头函数)
users = [
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25},
{"name": "Charlie", "age": 35}
]
# 按年龄排序
users_sorted = sorted(users, key=lambda u: u["age"])
# JS 对比:
// const usersSorted = users.sort((a, b) => a.age - b.age);
Python 的 lambda 比 JS 箭头函数受限更多:只能包含单个表达式,不能写语句(如赋值、循环)。
复杂逻辑应使用普通 def 函数。如果你需要类似 JS 箭头函数的灵活性,直接写命名函数即可。
生成器(Generator)—— 惰性计算的利器
生成器是 Python 最具特色的功能之一,它允许你按需生成数据,而不是一次性把所有数据加载到内存中。 如果把列表比作"一次性把所有菜端上桌",生成器就是"你点一道做一道"。
# === 生成器函数:使用 yield 逐值返回 ===
def fibonacci(n):
"""生成前 n 个斐波那契数(惰性生成,不占内存)"""
a, b = 0, 1
for _ in range(n):
yield a # yield 类似 return,但函数不会退出
a, b = b, a + b
# 使用生成器
for num in fibonacci(10):
print(num, end=" ") # 0 1 1 2 3 5 8 13 21 34
# 转为列表(惰性 -> 立即求值)
fib_list = list(fibonacci(10))
print(fib_list) # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
# === 生成器表达式(类似列表推导式,但用小括号)===
# 列表推导式:一次性创建所有元素(占内存)
squares_list = [x**2 for x in range(10**6)] # 100万个元素的列表
# 生成器表达式:按需生成(几乎不占内存)
squares_gen = (x**2 for x in range(10**6)) # 生成器对象
print(squares_gen) #
print(next(squares_gen)) # 0(取第一个值)
print(next(squares_gen)) # 1(取第二个值)
# === 实战:逐行读取大文件(不会撑爆内存)===
def read_large_file(filepath):
"""逐行读取文件,适合 GB 级别的大文件"""
with open(filepath, "r", encoding="utf-8") as f:
for line in f:
yield line.strip()
# 处理大文件
for line in read_large_file("big_data.log"):
if "ERROR" in line:
print(line)
| 特性 | 列表 | 生成器 |
|---|---|---|
| 内存占用 | 存储全部元素 | 只存储当前元素 |
| 遍历次数 | 可多次遍历 | 只能遍历一次 |
| 索引访问 | 支持 list[5] |
不支持 |
| 创建速度 | 慢(需要计算所有值) | 快(立即返回) |
| 适用场景 | 小数据、需要多次访问 | 大数据、流式处理、管道 |
| JS 类比 | Array | AsyncIterator / Generator |
2.5 面向对象
Python 的面向对象编程与 JavaScript 的 class 语法有许多相似之处,但也有独特的设计哲学。
类与实例
class User:
# 类属性(类似 JS 的静态属性,所有实例共享)
species = "Homo sapiens"
# __init__ 是构造方法(类似 JS 的 constructor)
def __init__(self, name, age):
# self 相当于 JS 的 this,但必须显式作为第一个参数
self.name = name # 实例属性
self._age = age # 单下划线表示"私有"(约定,非强制)
# 实例方法
def greet(self):
return f"Hello, I'm {self.name}"
# 类方法(类似 JS 的 static 方法,但接收 cls)
@classmethod
def create_anonymous(cls):
return cls("Anonymous", 0)
# 静态方法(类似 JS 的 static 方法,不接收 self/cls)
@staticmethod
def is_adult(age):
return age >= 18
# 创建实例(不需要 new 关键字!)
alice = User("Alice", 25)
print(alice.greet()) # Hello, I'm Alice
# 访问类属性
print(User.species) # Homo sapiens
| 特性 | JavaScript | Python |
|---|---|---|
| 实例引用 | this(隐式) |
self(必须显式声明) |
| 创建实例 | new User() |
User()(无 new) |
| 构造函数 | constructor() |
__init__(self) |
| 方法定义 | greet() {} |
def greet(self): |
继承
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError("子类必须实现此方法")
class Dog(Animal): # 继承语法: class 子类(父类)
def __init__(self, name, breed):
super().__init__(name) # 调用父类构造(类似 super())
self.breed = breed
def speak(self):
return f"{self.name} says: Woof!"
class Cat(Animal):
def speak(self):
return f"{self.name} says: Meow!"
dog = Dog("Buddy", "Golden Retriever")
cat = Cat("Whiskers")
print(dog.speak()) # Buddy says: Woof!
print(cat.speak()) # Whiskers says: Meow!
魔术方法(Dunder Methods)
魔术方法以双下划线开头和结尾,让你自定义类的行为,类似 JS 的 Symbol 方法:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
# 字符串表示(类似 JS 的 toString())
def __str__(self):
return f"Vector({self.x}, {self.y})"
# 开发者友好的表示(类似 JS 的 inspect 或 toJSON)
def __repr__(self):
return f"Vector(x={self.x}, y={self.y})"
# 加法运算符重载(JS 中需用 Symbol.toPrimitive 或 valueOf)
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
# 相等比较(类似 JS 的 == 或 Object.is)
def __eq__(self, other):
return self.x == other.x and self.y == other.y
# 长度(类似 JS 的 valueOf 或自定义属性)
def __len__(self):
return int((self.x ** 2 + self.y ** 2) ** 0.5)
v1 = Vector(2, 3)
v2 = Vector(4, 5)
print(str(v1)) # Vector(2, 3)
print(repr(v1)) # Vector(x=2, y=3)
print(v1 + v2) # Vector(6, 8)
print(v1 == Vector(2, 3)) # True
print(len(v1)) # 3
| Python | 作用 | JS 类比 |
|---|---|---|
__init__ |
构造函数 | constructor() |
__str__ |
用户友好的字符串 | toString() |
__repr__ |
开发者调试字符串 | inspect / 调试器显示 |
__eq__ |
== 比较 | [Symbol.toPrimitive] |
__len__ |
len() 函数 | .length getter |
__getitem__ |
索引访问 [] | Proxy get trap |
2.6 异常处理
Python 的异常处理结构与 JavaScript 的 try/catch 非常相似,但功能更完善,支持 else 和 finally 子句。
# 基础异常处理
def divide(a, b):
try:
result = a / b
except ZeroDivisionError:
print("错误:不能除以零!")
return None
except TypeError as e:
print(f"类型错误: {e}")
return None
else:
# try 成功执行且没有异常时运行
print("计算成功!")
return result
finally:
# 无论是否异常都会执行(常用于清理资源)
print("计算结束")
print(divide(10, 2)) # 计算成功! 计算结束 5.0
print(divide(10, 0)) # 错误:不能除以零! 计算结束 None
常见异常类型
| 异常类型 | 触发场景 | JS 类比 |
|---|---|---|
ValueError |
值类型正确但内容不合法 | RangeError / 类型转换错误 |
TypeError |
操作或函数应用于不适当类型 | TypeError |
KeyError |
字典中访问不存在的键 | 访问对象不存在的属性 |
IndexError |
序列索引超出范围 | RangeError(数组越界) |
FileNotFoundError |
文件不存在 | Node.js fs 模块错误 |
ImportError |
导入模块失败 | MODULE_NOT_FOUND |
自定义异常
# 继承 Exception 创建自定义异常(类似 JS 的 class extends Error)
class ValidationError(Exception):
"""数据验证失败时抛出"""
def __init__(self, field, message):
self.field = field
self.message = message
super().__init__(f"[{field}] {message}")
class User:
def __init__(self, name, age):
if not name or len(name) < 2:
raise ValidationError("name", "姓名至少需要 2 个字符")
if age < 0 or age > 150:
raise ValidationError("age", "年龄必须在 0-150 之间")
self.name = name
self.age = age
try:
user = User("A", 200)
except ValidationError as e:
print(f"验证失败: {e}")
# 输出: 验证失败: [name] 姓名至少需要 2 个字符
2.7 文件操作
Python 的文件操作比 Node.js 更直观,内置的 open() 函数和 with 语句让资源管理变得简单安全。
基础读写
# 写入文件(类似 fs.writeFileSync)
with open("hello.txt", "w", encoding="utf-8") as f:
f.write("Hello, Python!\n")
f.write("第二行内容\n")
# with 语句自动关闭文件,无需手动 f.close()
# 读取文件(类似 fs.readFileSync)
with open("hello.txt", "r", encoding="utf-8") as f:
content = f.read() # 读取全部内容
print(content)
# 逐行读取(类似 readline 接口)
with open("hello.txt", "r", encoding="utf-8") as f:
for line in f:
print(line.strip()) # strip() 去除换行符
# 读取为列表
with open("hello.txt", "r", encoding="utf-8") as f:
lines = f.readlines() # ['Hello, Python!\n', '第二行内容\n']
Windows 系统默认编码可能是 GBK,不指定 encoding 会导致中文乱码。
始终显式指定 encoding="utf-8",这是最佳实践。
with 语句与上下文管理器
# with 语句确保资源正确释放(类似 JS 的 try...finally)
# 即使发生异常,文件也会被关闭
# 传统写法(不推荐)
f = open("file.txt", "r")
try:
data = f.read()
finally:
f.close() # 必须手动关闭
# with 写法(推荐)
with open("file.txt", "r") as f:
data = f.read()
# 自动关闭,即使出错
# 自定义上下文管理器
from contextlib import contextmanager
@contextmanager
def managed_resource(name):
print(f"获取资源: {name}")
yield name # yield 之前的代码是 __enter__,之后是 __exit__
print(f"释放资源: {name}")
with managed_resource("数据库连接") as res:
print(f"使用资源: {res}")
# 输出:
# 获取资源: 数据库连接
# 使用资源: 数据库连接
# 释放资源: 数据库连接
pathlib —— 现代路径处理
pathlib 是 Python 3.4+ 引入的现代路径库,比传统的 os.path 更直观:
from pathlib import Path
# 创建路径对象(自动处理 Windows/Unix 路径差异)
project_dir = Path("/home/user/project")
data_file = project_dir / "data" / "users.json" # 使用 / 拼接路径!
print(data_file) # /home/user/project/data/users.json
print(data_file.name) # users.json(文件名)
print(data_file.stem) # users(不含扩展名)
print(data_file.suffix) # .json(扩展名)
print(data_file.parent) # /home/user/project/data(父目录)
# 路径检查
print(data_file.exists()) # False(检查是否存在)
print(data_file.is_file()) # False
print(data_file.is_dir()) # False
# 创建目录(类似 mkdir -p)
output_dir = Path("output")
output_dir.mkdir(parents=True, exist_ok=True)
# 遍历目录(类似 fs.readdir)
for file in Path(".").glob("*.py"): # 匹配当前目录的 .py 文件
print(file)
# 递归遍历
for file in Path(".").rglob("*.txt"): # 递归查找所有 .txt
print(file)
新项目优先使用 pathlib,API 更现代、面向对象、跨平台。
维护旧代码时可能会遇到 os.path,两者可以互相转换:
Path("file.txt").__str__() 得到字符串路径。
2.8 模块与包
Python 的模块系统与 JavaScript 的 ES Modules / CommonJS 类似,用于组织代码和复用功能。
导入模块
# 1. 导入整个模块(类似 import * as os from 'os')
import os
print(os.getcwd()) # 获取当前工作目录
# 2. 从模块导入特定内容(类似 import { pi, sin } from 'math')
from math import pi, sqrt
print(pi)
print(sqrt(16)) # 4.0
# 3. 导入并重命名(类似 import * as m from 'math')
import datetime as dt
now = dt.datetime.now()
# 4. 导入所有(不推荐,会污染命名空间)
from math import *
print(sin(pi / 2)) # 1.0
# 5. 相对导入(包内部使用)
# from . import module # 同级目录
# from .. import parent # 上级目录
# from .utils import helper # 子模块
__name__ == '__main__'
这是 Python 中最常见的惯用法,用于判断模块是被直接运行还是被导入:
# utils.py
def helper():
return "I'm a helper"
# 当直接运行 python utils.py 时,__name__ 是 '__main__'
# 当从其他文件 import utils 时,__name__ 是 'utils'
if __name__ == "__main__":
# 这部分代码只在直接运行时执行
print("测试 helper 函数:")
print(helper())
# JS 类比:
// if (require.main === module) { ... }
// 或 ES Module 的 import.meta.main
想象你写了一个工具模块,里面有一些测试代码。当你直接运行文件时,希望测试代码执行; 但当其他文件导入你的模块时,不希望测试代码干扰。这个惯用法完美解决了这个问题。
标准库简介
Python 以"内置电池"著称,标准库功能丰富。以下是前端开发者最常用的一些模块:
| 模块 | 用途 | 前端 / Node.js 类比 |
|---|---|---|
os |
操作系统接口 | os / process |
sys |
系统相关参数和函数 | process.argv, process.exit() |
pathlib |
面向对象的路径操作 | path 模块 |
json |
JSON 编码解码 | JSON.parse/stringify |
re |
正则表达式 | RegExp |
datetime |
日期和时间处理 | Date / dayjs |
collections |
高级数据结构 | — |
itertools |
迭代器工具 | — |
functools |
高阶函数工具 | — |
urllib |
URL 处理 | URL / URLSearchParams |
# 常用标准库示例
import json
from datetime import datetime, timedelta
# JSON 处理(与 JS 几乎相同)
data = {"name": "Alice", "age": 25}
json_str = json.dumps(data, ensure_ascii=False, indent=2)
parsed = json.loads(json_str)
# 日期时间(类似 dayjs/moment)
now = datetime.now()
future = now + timedelta(days=7)
print(future.strftime("%Y-%m-%d")) # 格式化输出
本章涵盖了 Python 的核心语法:变量与数据类型、四种核心数据结构(list/dict/tuple/set)、 控制流、函数定义(含 *args/**kwargs)、面向对象编程、异常处理、文件操作以及模块系统。
作为前端开发者,你会发现 Python 的语法更加简洁一致,而 JavaScript 的灵活性更高。 掌握这些基础后,你已经可以编写绝大多数 Python 脚本。下一章将介绍 Python 工程化实践, 包括项目结构、虚拟环境、测试和类型提示等内容。