1.概述

予早 2025-02-21 01:08:21
Categories: Tags:

Python代码规约

Python之禅

import this

"""
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
"""

PEP

Python Enhancement Proposals,PEP,python完善提案

https://www.python.org/dev/peps/

https://www.cnblogs.com/abella/p/10056875.html

PEP的状态

每个PEP都有一个状态,用于指示它的生命周期阶段。一些常见的PEP状态包括:

PEP的结构

PEP文档通常遵循特定的结构,包括标题、作者、提案摘要、动机、提案正文、实现细节、示例代码和参考文献等部分。熟悉PEP的结构可以帮助你更容易地理解其内容。

代码格式

基本风格

PEP8风格,PEP 8,Python Enhancement Proposal,Python增强指南,https://peps.python.org/pep-0008/,http://pep8.org/

https://zh-google-styleguide.readthedocs.io/en/latest/google-python-styleguide/python_style_rules/

https://pythonguidecn.readthedocs.io/zh/latest/writing/style.html

代码格式器

格式工具 格式风格
Black PEP8
yapf Google style
autopep8 PEP8

导包规约

  1. 禁止使用from xxx import *,应显示指明要导入的模块。from xxx import *会污染命名空间,被导入模块改动时可能会影响其他模块造成难以排查的问题。例外,在某些必须或惯用from xxx import *的场景下,必须使用__all__显示控制标识符的导出。

  2. import导入语句顺序,内置模块>三方模块或二方模块>一方模块,同级别遵循字典序。

  3. 仅导入模块需要使用注释注明用途。

  4. 不使用直接导入模块内成员的方式,降低命名空间污染程度。

    正例

    import datetime
    
    print(datetime.datetime.now())
    print(datetime.time())
    

    反例

    若后续需要导入Python标准库time就会导致问题。

    from datetime import time, datetime
    
    print(datetime.now())
    print(time())
    

    例外

    Python标准库typing使用与该规约恰恰相反。

    from typing import Any, List, Dict
    
  5. 一般项目中导包使用绝对导入方式,自定义库中使用相对导入方式。

命名规约

通用规则

  1. 避免使用中划线-

  2. 避免使用__xxx__形式名称,该形式名称保留给Python解释器使用。

  3. 尽量使用见名知意的命名。

  4. PEP 8: E741 ambiguous variable name ‘l’

    应避免使用字符I(i),O(O),L(l)来作为变量名,因为这些字符容易使人与数字1,0混淆

具体规则

标识符 公有 私有
包或模块名 lower_case_and_underline
类名 GreatHump
函数或方法名 lower_case_and_underline
变量名(全局变量、局部变量、函数或方法参数) lower_case_and_underline
常量名 GREAT_HUMP_AND_UNDERLINE

main规约

  1. 可执行Python脚本必须使用if __name__ == '__main__'限制只有在顶层代码环境才可执行。

  2. 禁止if __name__ == '__main__下有复杂逻辑,应将逻辑交由main方法承载并作为可执行脚本入口函数。if __name__ == '__main__'及其下代码属于全局作用域,可能会掩盖一部分问题。

    正例

    def main():
        ...
    
    if __name__ == "__main__":
      main()
    

    反例

    下方代码PyCharm不会检查出问题,但实际上,若某一个模块导入下方模块并调用函数func会出现问题NameError: name 'a' is not defined

    def func():
        print(a)
    
    
    if __name__ == '__main__':
        a = 1
    

注释规约

  1. 非直观代码需要注释

    正例

    # 若i为2的任意次方
    if i & (i - 1):
        ...
    

    反例

    # 遍历items
    for i in itmes:
        ...
    
  2. 代码更新时注释更新,具有误导性的错误注释比没有注释更糟糕

异常规约

  1. 自定义异常名以Error结尾,继承Exception
  2. 异常处理抛出异常实例Exception('xxx')而非异常类本身Exception

语法规约

  1. 禁止使用嵌套的简化if语句,嵌套的简化if语句极大降低代码可读性。

    正例

    if age < 18:
        a = 0
    else:
        a = 1 if age <= 60 else 2
    

    反例

    a = 0 if age < 18 else 1 if age <= 60 else 2
    
  2. 禁止使用可变对象作为函数或方法参数的默认值。函数参数默认值是函数的一部分,参数为可变类型会导致函数为有状态函数,造成潜在问题。

    反例

    def add_employee(names, emp_list=[]):
        for name in names:
            if check(name):
                emp_list.append(name)
        return emp_list
    
    
    print(add_employee(['张三', '李四']))  # ['张三', '李四']
    print(add_employee(['王五', '赵六']))  # ['张三', '李四', '王五', '赵六']
    

    正例

    def add_employee(names, emp_list=None):
        if emp_list is None:
            emp_list = []
        for name in names:
            if check(name):
                emp_list.append(name)
        return emp_list
    
    
    print(add_employee(['张三', '李四']))  # ['张三', '李四']
    print(add_employee(['王五', '赵六']))  # ['王五', '赵六']
    
  3. 需要列表下标使用enumerate

    正例

    for idx, item in enumerate(lst):
        print(idx, item)
    

    反例

    idx = 0
    for i in lst:
        print(idx, i)
        idx += 1
    
    
    for idx in range(len(lst)):
        print(idx, lst[idx])
    
  4. 交换变量

    正例

    x, y = y, x
    

    反例

    tmp = x
    x = y
    y = tmp
    
  5. 字典默认值处理

    反例

    words, frequency = [(1, 'apple'), (2, 'banana'), (1, 'cat')], {}
    
    for freq, word in words:
        if freq not in frequency:
            frequency[freq] = []
        frequency[freq].append(word)
    

    正例

    words, frequency = [(1, 'apple'), (2, 'banana'), (1, 'cat')], {}
    for freq, word in words:
        frequency.setdefault(freq, []).append(word)
    
    from collections import defaultdict
    
    words, frequency = [(1, 'apple'), (2, 'banana'), (1, 'cat')], defaultdict(list)
    
    for freq, word in words:
        frequency[freq].append(word)
    
  6. 善用key

    d = {"张三": 14, "李四": 12, "王五": 13}
    
    print(max(d, key=d.get))
    
    print(min(d, key=d.get))
    
    print(sorted(d, key=d.get))
    

代码结构规约

  1. 将相互关联的类以及函数放在一个模块中,不需要限制一个模块只能有一个类。