首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >同样的功能,为什么我的Python代码比你的优雅

同样的功能,为什么我的Python代码比你的优雅

作者头像
用户11081884
发布2026-07-29 20:28:21
发布2026-07-29 20:28:21
40
举报

上周review代码,同样的业务逻辑,有的写了50行,有的写了200行。不是算法多高明,而是几个简单的代码习惯,让同样的功能实现得更优雅、更易维护。

今天就来分享这些让Python代码变优雅的秘诀——不是炫技的技巧,而是每个Python开发者都应该掌握的基本功。


1. 善用内置函数和标准库,少造轮子

新手写法:

代码语言:javascript
复制
# 判断列表是否包含某个元素
defcontains_value(lst, target):
    foriteminlst:
        ifitem == target:
            returnTrue
    returnFalse

# 反转字符串
defreverse_string(s):
    result = ""
    foriinrange(len(s)-1, -1, -1):
        result += s[i]
    returnresult

# 统计单词频率
defcount_words(text):
    words = text.split()
    freq = {}
    forwordinwords:
        ifwordinfreq:
            freq[word] += 1
        else:
            freq[word] = 1
    returnfreq

优雅写法:

代码语言:javascript
复制
# 使用in运算符
targetinmy_list

# 使用切片反转
reversed_str = s[::-1]

# 使用collections.Counter
fromcollectionsimportCounter
freq = Counter(text.split())

# 更多内置函数示例
# 获取最大/最小值
max_value = max(numbers)
min_value = min(numbers, key=lambdax: x.score)

# 排序
sorted_users = sorted(users, key=lambdau: u.age, reverse=True)

# 映射和过滤
squares = map(lambdax: x**2, numbers)
evens = filter(lambdax: x%2 == 0, numbers)

# 使用列表推导式
squares = [x**2forxinnumbersifx>0]

Python内置的“瑞士军刀”:

  • collections:专用容器类型(Counter、defaultdict、deque)
  • itertools:迭代器工具(permutations、combinations、cycle)
  • functools:高阶函数(lru_cache、partial、reduce)
  • contextlib:上下文管理器工具
  • pathlib:现代化路径操作

2. 列表推导式 vs 传统循环,不仅仅是简洁

传统循环(啰嗦且易错):

代码语言:javascript
复制
# 过滤并转换数据
result = []
foritemindata:
    ifitem.is_valid():
        processed = process_item(item)
        ifprocessedisnotNone:
            result.append(processed)

# 嵌套循环生成矩阵
matrix = []
foriinrange(3):
    row = []
    forjinrange(3):
        row.append(i*j)
    matrix.append(row)

列表推导式(清晰且高效):

代码语言:javascript
复制
# 单行搞定过滤和转换
result = [process_item(item) foritemindata
          ifitem.is_valid() andprocess_item(item) isnotNone]

# 嵌套推导式生成矩阵
matrix = [[i*jforjinrange(3)] foriinrange(3)]

# 字典推导式
user_dict = {user.id: user.nameforuserinusersifuser.active}

# 集合推导式  
unique_words = {word.lower() forwordintext.split() iflen(word) >3}

什么时候用推导式?

  1. 简单转换/过滤:用推导式
  2. 复杂逻辑:用传统循环
  3. 需要副作用:用传统循环
  4. 可读性优先:如果推导式太长,拆成多行或改用循环

多行推导式的最佳实践:

代码语言:javascript
复制
# 不好的写法(太长了)
result = [transform(x) forxindataifcondition1(x) andcondition2(x) andcomplex_check(x)]

# 好的写法(清晰易读)
result = [
    transform(x)
    forxindata
    ifcondition1(x) 
    andcondition2(x) 
    andcomplex_check(x)
]

3. 函数设计:小而专,不要大而全

糟糕的函数(什么都要做):

代码语言:javascript
复制
defprocess_user_data(user_data, output_format='json', save_to_db=True, 
                     send_email=False, generate_report=True, log_level='info'):
    """
    这个函数做了太多事情:
    1. 验证数据
    2. 转换格式
    3. 保存到数据库
    4. 发送邮件
    5. 生成报告
    6. 记录日志
    """
    # 200行代码...
    pass

优雅的函数(单一职责):

代码语言:javascript
复制
# 拆分成多个小函数
defvalidate_user_data(data):
    """只负责验证"""
    ifnotdata.get('name'):
        raiseValidationError("姓名必填")
    ifnotdata.get('email'):
        raiseValidationError("邮箱必填")
    returnTrue

deftransform_to_model(validated_data):
    """只负责转换"""
    returnUserModel(**validated_data)

defsave_user(user_model):
    """只负责保存"""
    returndb.session.add(user_model)

defsend_welcome_email(user):
    """只负责发邮件"""
    email_service.send(user.email, "welcome_template")

# 组合使用
defcreate_user(user_data):
    """协调函数,组合小功能"""
    validate_user_data(user_data)
    user = transform_to_model(user_data)
    save_user(user)
    send_welcome_email(user)
    returnuser

函数设计原则:

  1. 单一职责:一个函数只做一件事
  2. 简短:最好不超过20行
  3. 明确命名:动词开头,说明做什么
  4. 参数合理:不超过3个,多用关键字参数
  5. 返回值一致:要么都返回,要么都不返回

使用类型提示:

代码语言:javascript
复制
fromtypingimportOptional, List, Dict

defcalculate_stats(
    numbers: List[float],
    method: str = 'mean'
) ->Dict[str, float]:
    """
    计算统计信息
    
    Args:
        numbers: 数字列表
        method: 计算方法 ('mean', 'median', 'mode')
    
    Returns:
        包含统计结果的字典
    """
    # 实现...
    pass

4. 上下文管理器:优雅的资源管理

新手写法(容易忘记关闭资源):

代码语言:javascript
复制
# 文件操作
file = open('data.txt', 'r')
try:
    content = file.read()
    # 处理内容...
finally:
    file.close()

# 数据库连接
conn = create_connection()
try:
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM users")
    # 处理结果...
finally:
    conn.close()

# 锁操作
lock = threading.Lock()
lock.acquire()
try:
    # 临界区代码...
finally:
    lock.release()

优雅写法(自动管理资源):

代码语言:javascript
复制
# 使用with语句
withopen('data.txt', 'r') asfile:
    content = file.read()
    # 文件会自动关闭

withcreate_connection() asconn:
    withconn.cursor() ascursor:
        cursor.execute("SELECT * FROM users")
        # 连接和游标都会自动关闭

withthreading.Lock():
    # 临界区代码,锁会自动释放

# 更多内置上下文管理器
importtempfile
withtempfile.TemporaryDirectory() astmpdir:
    # 临时目录会自动清理

importsqlite3
withsqlite3.connect('database.db') asconn:
    # 数据库连接自动管理

自定义上下文管理器:

代码语言:javascript
复制
fromcontextlibimportcontextmanager
importtime

@contextmanager
deftimer(name: str):
    """计时上下文管理器"""
    start = time.time()
    try:
        yield
    finally:
        elapsed = time.time() -start
        print(f"{name}耗时: {elapsed:.3f}秒")

# 使用
withtimer("数据处理"):
    process_large_dataset()

# 更复杂的例子
@contextmanager
defdatabase_transaction(db_url: str):
    """数据库事务管理器"""
    conn = create_connection(db_url)
    try:
        yieldconn
        conn.commit()  # 成功时提交
    exceptException:
        conn.rollback()  # 失败时回滚
        raise
    finally:
        conn.close()

withdatabase_transaction("postgresql://localhost/db") asconn:
    conn.execute("INSERT INTO users VALUES (...)")

5. 装饰器:增强功能而不修改代码

新手写法(重复代码):

代码语言:javascript
复制
defprocess_order(order_data):
    # 记录开始时间
    start = time.time()
    
    try:
        # 业务逻辑
        result = validate_order(order_data)
        result = calculate_price(result)
        result = apply_discount(result)
        
        # 记录结束时间
        elapsed = time.time() -start
        print(f"订单处理耗时: {elapsed:.3f}秒")
        
        returnresult
    exceptExceptionase:
        # 记录错误
        print(f"订单处理失败: {e}")
        raise

defgenerate_report(report_data):
    # 重复的计时和错误处理代码
    start = time.time()
    
    try:
        # 业务逻辑
        result = analyze_data(report_data)
        result = format_report(result)
        
        elapsed = time.time() -start
        print(f"报告生成耗时: {elapsed:.3f}秒")
        
        returnresult
    exceptExceptionase:
        print(f"报告生成失败: {e}")
        raise

优雅写法(使用装饰器):

代码语言:javascript
复制
fromfunctoolsimportwraps
importtime
importlogging

logger = logging.getLogger(__name__)

deftimer(func):
    """计时装饰器"""
    @wraps(func)
    defwrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        elapsed = time.time() -start
        logger.info(f"{func.__name__}耗时: {elapsed:.3f}秒")
        returnresult
    returnwrapper

deflog_errors(func):
    """错误日志装饰器"""
    @wraps(func)
    defwrapper(*args, **kwargs):
        try:
            returnfunc(*args, **kwargs)
        exceptExceptionase:
            logger.error(f"{func.__name__}执行失败: {e}", exc_info=True)
            raise
    returnwrapper

defretry(max_attempts=3, delay=1):
    """重试装饰器"""
    defdecorator(func):
        @wraps(func)
        defwrapper(*args, **kwargs):
            forattemptinrange(max_attempts):
                try:
                    returnfunc(*args, **kwargs)
                exceptExceptionase:
                    ifattempt == max_attempts-1:
                        raise
                    logger.warning(f"第{attempt+1}次尝试失败,{delay}秒后重试: {e}")
                    time.sleep(delay)
            returnNone
        returnwrapper
    returndecorator

# 使用装饰器
@timer
@log_errors
@retry(max_attempts=3)
defprocess_order(order_data):
    """现在只关注业务逻辑"""
    result = validate_order(order_data)
    result = calculate_price(result)
    result = apply_discount(result)
    returnresult

@timer
@log_errors
defgenerate_report(report_data):
    """同样只关注业务逻辑"""
    result = analyze_data(report_data)
    result = format_report(result)
    returnresult

常用装饰器模式:

代码语言:javascript
复制
# 缓存装饰器
fromfunctoolsimportlru_cache

@lru_cache(maxsize=128)
defexpensive_calculation(x):
    # 耗时计算,结果会被缓存
    time.sleep(1)
    returnx*x

# 类型检查装饰器
fromtypingimportget_type_hints

deftypechecked(func):
    """运行时类型检查"""
    @wraps(func)
    defwrapper(*args, **kwargs):
        # 获取类型提示
        hints = get_type_hints(func)
        
        # 检查参数类型
        for (arg_name, arg_value), (param_name, param_type) inzip(
            enumerate(args), hints.items()
        ):
            ifnotisinstance(arg_value, param_type):
                raiseTypeError(f"参数{param_name}应该是{param_type}类型")
        
        returnfunc(*args, **kwargs)
    returnwrapper

6. 数据类:替代繁琐的init方法

传统写法(样板代码多):

代码语言:javascript
复制
classUser:
    def__init__(self, name, email, age, address=None, phone=None):
        self.name = name
        self.email = email
        self.age = age
        self.address = address
        self.phone = phone
    
    def__repr__(self):
        returnf"User(name={self.name!r}, email={self.email!r}, age={self.age})"
    
    def__eq__(self, other):
        ifnotisinstance(other, User):
            returnFalse
        return (self.name == other.nameand
                self.email == other.emailand
                self.age == other.age)
    
    defto_dict(self):
        return {
            'name': self.name,
            'email': self.email,
            'age': self.age,
            'address': self.address,
            'phone': self.phone
        }

优雅写法(使用数据类):

代码语言:javascript
复制
fromdataclassesimportdataclass, asdict, field
fromtypingimportOptional

@dataclass
classUser:
    name: str
    email: str
    age: int
    address: Optional[str] = None
    phone: Optional[str] = None
    tags: list[str] = field(default_factory=list)
    
    @property
    defis_adult(self):
        returnself.age>= 18
    
    defgreet(self):
        returnf"你好,{self.name}!"

# 自动获得的功能:
# 1. __init__方法
# 2. __repr__方法
# 3. __eq__方法
# 4. 不可变版本(frozen=True)
# 5. 排序支持(order=True)

# 使用
user = User("张三", "zhang@example.com", 25)
print(user)  # User(name='张三', email='zhang@example.com', age=25)
print(user == User("张三", "zhang@example.com", 25))  # True
print(asdict(user))  # 转换为字典

7. 现代字符串格式化:告别丑陋的拼接

过时的写法:

代码语言:javascript
复制
# %格式化(Python 2风格)
message = "用户%s,年龄%d,余额%.2f"% (name, age, balance)

# str.format()(Python 3早期)
message = "用户{},年龄{},余额{:.2f}".format(name, age, balance)
message = "用户{name},年龄{age}".format(name=name, age=age)

# 字符串拼接(最差)
message = "用户"+name+",年龄"+str(age) +",余额"+format(balance, ".2f")

现代写法(f-string):

代码语言:javascript
复制
# Python 3.6+ 推荐
name = "张三"
age = 25
balance = 1234.5678

# 基本用法
message = f"用户{name},年龄{age},余额{balance:.2f}"

# 表达式支持
score = 85
result = f"成绩: {score}, 状态: {'及格' if score >= 60 else '不及格'}"

# 函数调用
defget_title(user):
    return"先生"ifuser.gender == 'M'else"女士"

message = f"尊敬的{get_title(user)}{user.name},您好!"

# 多行f-string
message = f"""
用户信息:
姓名:{user.name}
年龄:{user.age}
邮箱:{user.email}
注册时间:{user.created_at:%Y-%m-%d %H:%M}
"""

# 调试专用(Python 3.8+)
print(f"{user.name=} {user.age=} {user.score=}")
# 输出:user.name='张三' user.age=25 user.score=85

8. 错误处理:不要滥用try-except

糟糕的错误处理:

代码语言:javascript
复制
# 过于宽泛
try:
    result = do_something()
    result = do_another_thing(result)
    save_to_database(result)
exceptException:  # 捕获所有异常,隐藏问题
    pass

# 重复的异常处理
try:
    file = open('data.txt', 'r')
    content = file.read()
exceptFileNotFoundError:
    print("文件不存在")
exceptPermissionError:
    print("没有权限")
exceptExceptionase:
    print(f"未知错误: {e}")

# 忽略异常
try:
    risky_operation()
except:
    pass  # 静默失败,难以调试

优雅的错误处理:

代码语言:javascript
复制
# 1. 只捕获你能处理的异常
try:
    config = load_config('config.yaml')
exceptFileNotFoundError:
    # 文件不存在,使用默认配置
    config = get_default_config()
exceptyaml.YAMLErrorase:
    # 配置文件格式错误,记录并退出
    logger.error(f"配置文件格式错误: {e}")
    sys.exit(1)
# 让其他异常向上传播

# 2. 使用上下文管理器简化资源清理
fromcontextlibimportsuppress

# 忽略特定异常
withsuppress(FileNotFoundError):
    os.remove('temp_file.txt')

# 3. 自定义异常层次
classAppError(Exception):
    """应用基础异常"""
    pass

classValidationError(AppError):
    """验证错误"""
    pass

classDatabaseError(AppError):
    """数据库错误"""
    pass

# 使用时
defcreate_user(user_data):
    ifnotuser_data.get('email'):
        raiseValidationError("邮箱不能为空")
    
    try:
        db.save(user_data)
    exceptConnectionErrorase:
        raiseDatabaseError("数据库连接失败") frome

# 4. 使用else和finally
try:
    result = risky_operation()
exceptOperationErrorase:
    logger.error(f"操作失败: {e}")
    result = None
else:
    # 只有在try成功时才执行
    logger.info(f"操作成功,结果: {result}")
finally:
    # 无论成功失败都执行
    cleanup_resources()

优雅的代码的关键点:

第一层:基础规范

  • 使用有意义的变量名
  • 保持函数简短
  • 添加文档字符串

第二层:Python特性

  • 善用内置函数和标准库
  • 掌握推导式
  • 使用上下文管理器

第三层:设计模式

  • 函数单一职责
  • 使用装饰器增强功能
  • 合理设计异常体系

第四层:工程实践

  • 类型提示
  • 单元测试
  • 代码审查
代码审查清单

下次review代码时,问自己这几个问题:

  1. 可读性:不看注释能看懂吗?
  2. 简洁性:有没有更简单的写法?
  3. 可维护性:三个月后还能看懂吗?
  4. 健壮性:边界情况和错误处理了吗?
  5. 性能:有没有明显的性能问题?

“无他,惟手熟尔”!有需要的用起来!

如果你觉得这篇文章有用,欢迎点赞、转发、收藏、留言、推荐❤!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-07-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Nicholas与Pypi 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 善用内置函数和标准库,少造轮子
  • 2. 列表推导式 vs 传统循环,不仅仅是简洁
  • 3. 函数设计:小而专,不要大而全
  • 4. 上下文管理器:优雅的资源管理
  • 5. 装饰器:增强功能而不修改代码
  • 6. 数据类:替代繁琐的init方法
  • 7. 现代字符串格式化:告别丑陋的拼接
  • 8. 错误处理:不要滥用try-except
  • 优雅的代码的关键点:
  • 代码审查清单
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档