12个优秀的 Python 编码实践:提高代码可读性与可维护性

在日常工作中,我们始终追求让代码尽可能可读且易于理解。这不仅有助于团队协作,还能降低代码维护的成本。为了达到这一目标,我们需要遵循一些基本的编码原则,包括但不限于:

  • 变量名应具有意义且尽可能详尽:避免使用 a, b, c 之类的简短命名。
  • 函数名应明确描述功能:确保函数名能够清晰传达其用途。
  • 编写详尽的注释和文档:解释代码的功能和逻辑,便于他人理解和维护。
  • 使用类型提示:确保代码类型安全且便于理解。
  • 字符串内容应详细且描述性强:避免使用简短或模糊的字符串。

本文将分享我在实际生产环境中积累的 Python 代码风格技巧,帮助你提高代码的可读性和可维护性。

1. 带括号的元组解包

常见的元组解包方式如下:

a, b = (1, 2)

在生产环境中,我们通常避免使用 ab 这样的短变量名,而是使用更具描述性的变量名。这时,添加括号可以让解包代码更加清晰:

(long_variable_name_1, long_variable_name_2) = (1, 2)

一个更实际的例子:

(employee_name, employee_id, employee_department) = ("Alice", 1001, "Engineering")

括号的使用在长变量名的解包场景中显得尤为直观。

2. 多行列表推导式

通常的列表推导式如下:

squared_numbers = [i ** 2 for i in range(10)]

在生产代码中,变量名通常更长,使得单行表达式难以阅读。这时,可以将列表推导式拆分为多行:

squared_numbers = [
    number ** 2
    for number in range(10)
]

更实际的例子:

filtered_data = [
    item
    for item in dataset
    if item.get("is_active") and item.get("category") == "A"
]
3. 使用括号拼接字符串

长字符串在生产代码中很常见,直接写在一行可能不够直观。这时,可以通过括号分行拼接字符串:

error_message = (
    "An unexpected error occurred while processing the "
    "request. Please try again later or contact support."
)

注意:在括号内拼接字符串时,无需使用 + 运算符,Python 会自动将多行字符串拼接。

4. 使用括号进行多行方法链

普通的链式调用可能如下:

result = data.filter().sort().map()

在生产环境中,方法名可能更长,链式调用也可能更复杂,可以使用括号拆分为多行:

result = (
    data
    .filter_by_condition(condition="active")
    .sort_by_key(key="timestamp", reverse=True)
    .map_to_new_format()
)

此时不需要使用反斜杠 \,代码会更加简洁。

5. 多行索引嵌套字典

嵌套字典的常规索引方式如下:

value = nested_dict["key1"]["key2"]["key3"]

生产代码中嵌套层次较多时,可以使用多行索引提升可读性:

value = (
    nested_dict["key1"]
    ["key2"]
    ["key3"]
)

或更进一步,将索引操作分步实现:

level1 = nested_dict["key1"]
level2 = level1["key2"]
value = level2["key3"]
6. 编写可读且信息丰富的函数

学生时代可能会这样写函数:

def calculate(a, b):
    return a + b

然而,这种函数在代码审查时大概率会被拒绝,因为:

  • 函数名缺乏描述性。
  • 参数名过于简短。
  • 缺少类型提示,无法直观判断参数和返回值类型。
  • 缺少文档字符串,函数功能不明确。

改进后的函数如下:

def calculate_sum(value1: int, value2: int) -> int:
    """
    计算两个整数的和。

    参数:
        value1: 第一个整数。
        value2: 第二个整数。

    返回:
        两个整数的和。
    """
    return value1 + value2
7. 尽量减少嵌套层级

如下代码中,嵌套层级较深:

for item in items:
    if condition:
        do_something(item)

可以通过减少嵌套层级优化:

for item in items:
    if not condition:
        continue
    do_something(item)

这样可以显著提高代码的可读性。

8. 带括号的布尔条件

条件较短时通常写在一行:

if a and b and c:
    ...

但当条件较长时,可以使用括号分行:

if (
    is_valid(user)
    and has_permission(user, "edit")
    and not is_suspended(user)
):
    ...
9. 保护 None 值的访问

如下代码可能会因 None 引发错误:

if dog.owner.name == "bob":
    ...

在生产代码中,应保护对 None 的访问:

if dog and dog.owner and dog.owner.name == "bob":
    ...

短路运算符 andor 的使用可以有效避免不必要的异常。

10. 保护迭代时的 None 值

迭代前应确保变量为可迭代对象:

for item in mylist or []:
    ...

这样,即使 mylistNone,代码也能正常运行。

11. 内部函数以 _ 开头

以下类的方法缺乏内部和外部的区分:

class Example:
    def clean(self):
        ...

    def transform(self):
        ...

    def run(self):
        self.clean()
        self.transform()

在生产代码中,内部方法通常以 _ 开头,以显式区分:

class Example:
    def _clean(self):
        ...

    def _transform(self):
        ...

    def run(self):
        self._clean()
        self._transform()
12. 使用装饰器简化通用功能

如下代码存在重复的 try-except 和日志逻辑:

def func1():
    try:
        ...
    except Exception as e:
        log_error(e)

def func2():
    try:
        ...
    except Exception as e:
        log_error(e)

可以通过装饰器简化:

def log_and_catch(func):
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception as e:
            log_error(e)
    return wrapper

@log_and_catch
def func1():
    ...

@log_and_catch
def func2():
    ...

通过以上技巧,您的 Python 代码将更加专业、高效和易于维护。