如果你刚接触 Python,可能会听到“语法糖”这个词。它听起来很甜,实际上也确实能让你的代码写起来更甜——语法糖就是那些让代码更简洁、更易读、更符合直觉的语法特性,它们不会改变程序的功能,但能极大地提升开发效率和代码可维护性。
本文将系统梳理 Python 中常用的语法糖,每一条都配以清晰的示例。掌握了它们,你的 Python 代码将更加 Pythonic。
一、变量交换:a, b = b, a
其他语言需要临时变量,Python 一行搞定:
a, b = 5, 10a, b = b, aprint(a, b) # 10 5
a, b = 5, 10
a, b = b, a
print(a, b) # 10 5
原理:Python 会先计算右边的元组 (b, a),再赋值给左边的变量。
二、链式比较:a < b < c
数学中的写法在 Python 中完全合法:
x = 5if 1 < x < 10: print("x 在 1 到 10 之间")# 等价于 (1 < x) and (x < 10),但更加直观还可以串联 ==、in 等运算符:a = [1, 2, 3]if 1 in a and 2 in a: # 原始写法 passif 1 in a and 2 in a: # 还是需要 and,因为没有 in 的链式 pass# 但数值比较真的很爽
x = 5
if 1 < x < 10:
print("x 在 1 到 10 之间")
# 等价于 (1 < x) and (x < 10),但更加直观
还可以串联 ==、in 等运算符:
a = [1, 2, 3]
if 1 in a and 2 in a: # 原始写法
pass
if 1 in a and 2 in a: # 还是需要 and,因为没有 in 的链式
# 但数值比较真的很爽
三、列表/字典/集合推导式
这是 Python 最甜也最常用的语法糖之一:
# 列表推导:平方数squares = [x**2 for x in range(10)]# 带条件:偶数平方even_squares = [x**2 for x in range(10) if x % 2 == 0]# 字典推导square_dict = {x: x**2 for x in range(5)}# 集合推导unique_lengths = {len(word) for word in ["hello", "world", "python"]}
# 列表推导:平方数
squares = [x**2 for x in range(10)]
# 带条件:偶数平方
even_squares = [x**2 for x in range(10) if x % 2 == 0]
# 字典推导
square_dict = {x: x**2 for x in range(5)}
# 集合推导
unique_lengths = {len(word) for word in ["hello", "world", "python"]}
生成器表达式则把 [] 换成 (),实现惰性求值。
四、装饰器:@decorator
装饰器可以在不修改函数定义的情况下,给函数增加额外功能(日志、计时、权限等)。
def timer(func): import time def wrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) print(f"耗时 {time.time()-start:.4f}s") return result return wrapper@timerdef long_task(): time.sleep(1)long_task() # 输出耗时@timer 等价于 long_task = timer(long_task)。
def timer(func):
import time
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(f"耗时 {time.time()-start:.4f}s")
return result
return wrapper
@timer
def long_task():
time.sleep(1)
long_task() # 输出耗时
@timer 等价于 long_task = timer(long_task)。
五、with 语句与上下文管理器
自动管理资源(文件、锁、数据库连接等),避免忘记关闭。
# 传统写法:需要手动 closef = open('file.txt', 'r')data = f.read()f.close()# with 语法糖:自动关闭with open('file.txt', 'r') as f: data = f.read()# 自定义上下文管理器class ManagedFile: def __enter__(self): print("打开资源") return self def __exit__(self, exc_type, exc_val, exc_tb): print("关闭资源")with ManagedFile() as mf: print("使用资源")
# 传统写法:需要手动 close
f = open('file.txt', 'r')
data = f.read()
f.close()
# with 语法糖:自动关闭
with open('file.txt', 'r') as f:
# 自定义上下文管理器
class ManagedFile:
def __enter__(self):
print("打开资源")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("关闭资源")
with ManagedFile() as mf:
print("使用资源")
六、*args 与 **kwargs —— 参数打包与解包
用于定义可变参数函数,或者将列表/字典拆解为参数:
# 定义时打包def func(*args, **kwargs): print(args) # 元组 print(kwargs) # 字典func(1, 2, 3, name="Alice", age=25)# 调用时解包lst = [1, 2, 3]func(*lst) # 等价于 func(1, 2, 3)dct = {"name": "Bob", "age": 30}func(**dct) # 等价于 func(name="Bob", age=30)
# 定义时打包
def func(*args, **kwargs):
print(args) # 元组
print(kwargs) # 字典
func(1, 2, 3, name="Alice", age=25)
# 调用时解包
lst = [1, 2, 3]
func(*lst) # 等价于 func(1, 2, 3)
dct = {"name": "Bob", "age": 30}
func(**dct) # 等价于 func(name="Bob", age=30)
七、解包赋值:* 与 _
# 取出第一个和最后一个first, *middle, last = [10, 20, 30, 40, 50]print(first, middle, last) # 10 [20,30,40] 50# 忽略不需要的值_, _, third = (1, 2, 3)print(third) # 3
# 取出第一个和最后一个
first, *middle, last = [10, 20, 30, 40, 50]
print(first, middle, last) # 10 [20,30,40] 50
# 忽略不需要的值
_, _, third = (1, 2, 3)
print(third) # 3
八、else 子句:for-else、while-else、try-else
这可能是 Python 中最容易被忽略的语法糖,但在特定场景下非常有用。
# for-else: 循环没有被 break 打断时执行 elsefor n in range(2, 10): for x in range(2, n): if n % x == 0: break else: print(n, "是质数")# try-else: 没有异常时执行try: result = 10 / 2except ZeroDivisionError: print("除以零")else: print("无异常,结果为", result)
# for-else: 循环没有被 break 打断时执行 else
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
break
else:
print(n, "是质数")
# try-else: 没有异常时执行
try:
result = 10 / 2
except ZeroDivisionError:
print("除以零")
print("无异常,结果为", result)
九、@property —— 将方法变成属性
让你像访问属性一样调用方法,同时可以添加校验逻辑。
class Circle: def __init__(self, radius): self._radius = radius @property def radius(self): return self._radius @radius.setter def radius(self, value): if value < 0: raise ValueError("半径不能为负") self._radius = value @property def area(self): return 3.14 * self._radius ** 2c = Circle(5)print(c.radius) # 5,像属性一样c.radius = 10 # 自动调用 setterprint(c.area) # 314.0
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value < 0:
raise ValueError("半径不能为负")
self._radius = value
def area(self):
return 3.14 * self._radius ** 2
c = Circle(5)
print(c.radius) # 5,像属性一样
c.radius = 10 # 自动调用 setter
print(c.area) # 314.0
十、enumerate 代替手动计数器
words = ["apple", "banana", "cherry"]for i, word in enumerate(words, start=1): print(f"{i}: {word}")
words = ["apple", "banana", "cherry"]
for i, word in enumerate(words, start=1):
print(f"{i}: {word}")
十一、zip 并行遍历
names = ["Alice", "Bob"]ages = [25, 30]for name, age in zip(names, ages): print(f"{name} is {age} years old")
names = ["Alice", "Bob"]
ages = [25, 30]
for name, age in zip(names, ages):
print(f"{name} is {age} years old")
十二、any 与 all
nums = [1, 2, 3, 0, 4]if any(x == 0 for x in nums): print("包含 0")if all(x > 0 for x in nums): print("全为正数")
nums = [1, 2, 3, 0, 4]
if any(x == 0 for x in nums):
print("包含 0")
if all(x > 0 for x in nums):
print("全为正数")
十三、if x is None 而不是 if x == None
更精确的比较,推荐使用 is 判断单例对象 None、True、False。
x = Noneif x is None: print("x is None")
x = None
if x is None:
print("x is None")
十四、getattr、setattr、hasattr 动态访问属性
class User: name = "Alice"print(getattr(User, 'name', 'default')) # Alicesetattr(User, 'age', 25)print(User.age) # 25
class User:
name = "Alice"
print(getattr(User, 'name', 'default')) # Alice
setattr(User, 'age', 25)
print(User.age) # 25
十五、字符串乘法与列表乘法
print('-' * 20) # 打印分隔线zeros = [0] * 5 # [0, 0, 0, 0, 0]
print('-' * 20) # 打印分隔线
zeros = [0] * 5 # [0, 0, 0, 0, 0]
十六、__slots__ 节省内存(进阶)
虽然不是语法糖,但能让类实例不再拥有 __dict__,大幅减少内存占用。
class Point: __slots__ = ('x', 'y') def __init__(self, x, y): self.x = x self.y = y# 不能再动态添加新属性,但访问速度更快,内存更省
class Point:
__slots__ = ('x', 'y')
def __init__(self, x, y):
self.x = x
self.y = y
# 不能再动态添加新属性,但访问速度更快,内存更省
十七、三元表达式:x if condition else y
age = 20status = "成年" if age >= 18 else "未成年"
age = 20
status = "成年" if age >= 18 else "未成年"
十八、链式调用(方法返回 self)
虽然不是语言原生语法,但通过设计模式实现,常见于 ORM 和构建器模式:
class Person: def set_name(self, name): self.name = name return self def set_age(self, age): self.age = age return selfp = Person().set_name("Tom").set_age(20)
class Person:
def set_name(self, name):
self.name = name
def set_age(self, age):
self.age = age
p = Person().set_name("Tom").set_age(20)
十九、上下文管理器的 @contextlib.contextmanager 装饰器
用生成器快速编写上下文管理器:
from contextlib import contextmanager@contextmanagerdef tag(name): print(f"<{name}>") yield print(f"")with tag("h1"): print("这是标题")# 输出:
from contextlib import contextmanager
@contextmanager
def tag(name):
print(f"<{name}>")
yield
print(f"")
with tag("h1"):
print("这是标题")
# 输出:
# 输出:<h1> 这是标题 </h1>
二十、f-strings(Python 3.6+)
最直观的字符串格式化:
name = "Alice"age = 25print(f"{name} is {age} years old, next year {age+1}")
age = 25
print(f"{name} is {age} years old, next year {age+1}")
支持表达式、函数调用、格式限定符。
总结
a < b < c
[x**2 for x in range(10)]
@decorator
with open() as f
*args, **kwargs
for-else
enumerate
zip
x if cond else y
f"{var}"
学会使用这些语法糖,你的 Python 代码将更加清晰、简洁、优雅。但也注意不要滥用——过度的语法糖可能会降低可读性(比如过长的推导式)。找到平衡,写出让人愉悦的代码。
商务合作:RYXtest