写了几年代码,回头看自己以前的代码,常常有种"我当年怎么会这么写"的感觉。
代码风格不是花架子。它体现的是对语言的理解程度,对可读性的重视程度,以及对工程化的认知程度。同样的功能,新手和老手写出来的代码可能有天壤之别。
来看几个典型的例子。
判断条件:elif还是多个if
处理多条件分支时,新手容易写出这样的代码:
status = "pending"if status == "pending": print("等待处理")if status == "approved": print("审核通过")if status == "rejected": print("审核拒绝")if status == "completed": print("已完成")
这段代码能跑,但有明显的风格问题:即使匹配了某个条件,后面的if还是会继续判断,白白浪费计算资源。if-elif-else链才是正确的选择:
status = "pending"if status == "pending": print("等待处理")elif status == "approved": print("审核通过")elif status == "rejected": print("审核拒绝")elif status == "completed": print("已完成")else: print("未知状态")
elif告诉阅读者:这些条件是互斥的,匹配到一个就不会再匹配其他。代码意图更清晰,执行也更高效。
列表操作:循环还是推导式
筛选一个列表中符合条件的元素:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]result = []for n in numbers: if n % 2 == 0: result.append(n * 2)print(result) # [4, 8, 12, 16, 20]
功能没问题,但Pythonic的写法只需要一行:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]result = [n * 2 for n in numbers if n % 2 == 0]print(result) # [4, 8, 12, 16, 20]
列表推导式是Python最标志性的语法之一,不仅更简洁,执行速度也通常比显式循环快。习惯用推导式后,你会发现自己很少再写result = []然后循环append这种模式了。
字典也有推导式:
users = [ {"name": "张三", "age": 25}, {"name": "李四", "age": 30}, {"name": "王五", "age": 22}]name_to_age = {}for user in users: name_to_age[user["name"]] = user["age"]name_to_age = {user["name"]: user["age"] for user in users}
交换变量:temp中间变量还是元组解包
交换两个变量的值:
a = 10b = 20temp = aa = bb = tempprint(a, b) # 20 10
Python支持元组解包,一行搞定:
a = 10b = 20a, b = b, aprint(a, b) # 20 10
元组解包不仅用于变量交换,在函数返回多个值、循环解包等场景都很常见:
def get_stats(numbers): return min(numbers), max(numbers), sum(numbers) / len(numbers)low, high, avg = get_stats([1, 5, 3, 9, 2])pairs = [("a", 1), ("b", 2), ("c", 3)]for key, value in pairs: print(f"{key}: {value}")
函数参数:位置参数还是命名参数
调用有多参数的函数时:
def create_user(name, age, city, email, phone): return {"name": name, "age": age, "city": city, "email": email, "phone": phone}user = create_user("张三", 25, "北京", "zhang@example.com", "13800138000")
看这段代码,你能分清"北京"是哪个参数吗?几个字符串堆在一起,可读性很差。命名参数让调用代码自文档化:
user = create_user( name="张三", age=25, city="北京", email="zhang@example.com", phone="13800138000")
不仅参数含义一目了然,顺序也灵活了——命名参数可以打乱顺序:
user = create_user( email="li@example.com", name="李四", phone="13900139000", age=30, city="上海")
异常处理:裸except还是精确捕获
捕获异常时,新手往往过于宽泛:
try: result = risky_operation() print(result)except: print("出错了")
裸except捕获所有异常,包括KeyboardInterrupt(用户按Ctrl+C)、SystemExit(程序退出)。这不是好的工程实践。应该精确捕获你预期的异常类型:
try: result = json.loads(user_input)except ValueError as e: print(f"JSON格式错误: {e}")except KeyError as e: print(f"缺少必要字段: {e}")except Exception as e: print(f"未知错误: {e}") raise # 重新抛出,让上层处理
同时,避免在异常处理中默默吞掉错误,至少要记录日志:
import logginglogger = logging.getLogger(__name__)try: process_data()except DataFormatError as e: logger.warning(f"数据格式错误,跳过处理: {e}")except DatabaseError as e: logger.error(f"数据库错误,需要关注: {e}") raise # 数据库问题不能忽略,重新抛出except Exception as e: logger.exception("Unexpected error") # 记录完整堆栈 raise
字符串拼接:+号还是f-string
拼接字符串时:
name = "张三"age = 28city = "深圳"message = "姓名: " + name + ", 年龄: " + str(age) + ", 城市: " + city
类型转换、引号嵌套,代码看起来很乱。Python 3.6引入的f-string让这件事变得优雅:
message = f"姓名: {name}, 年龄: {age}, 城市: {city}"
f-string不仅更简洁,还支持表达式和格式化:
price = 99.8f"总价: {price * 1.13:.2f}元"f"比例: {0.258:.1%}" # 25.8%f"宽度: {42:05d}" # 00042f"大写: {name.upper()}"
None检查:== None还是is None
检查变量是否为None:
value = Noneif value == None: print("值为空")
==调用的是对象的__eq__方法,而某些对象可能重写这个方法导致意外结果。is比较的是对象身份(内存地址),更准确,也更Pythonic:
if value is None: print("值为空")if result is not None: print(f"结果: {result}")
这是PEP 8的风格规范,所有有经验的Python开发者都应该知道。
写在最后
代码风格不是吹毛求疵。好的风格让代码更易读、更易维护、也更容易被团队协作。
这些差异背后其实是思维方式的不同:老手习惯用Python的方式思考问题,而不是把其他语言的习惯带过来。Python有自己的哲学,"Simple is better than complex"。
你身边有没有"代码一看就是老手写的"的感觉?想听更多关于代码风格的话题,或者你有什么自己的心得?评论区见。