Python-编码规范

TomTao626 于 2019-04-13 发布
🥰本站访客数 👀本文阅读量

python中的DocStrings(解释文档)有什么作用

# DocStrings 的主要作用就是解释代码的作用,让其他人读你的代码时候,能更快速理解代码的作用是什么。
# 当定义一个函数后,我们可以在函数的第一行使用一对三个单引号 ''' 或者一对三个双引号 """ 来定义一个文档字符串,该文档字符串就是该函数的解释文档。
# 使用 __doc__(注意双下划线)调用函数中的文档字符串属性(注意,文中出现的反斜杠是转义符,去除一些符号的特殊格式)
def get_max(x,y):
    '''
    比较取出两个int类型中较大的那个数
    :param x: int类型数字
    :param y: int类型数字
    :return: 输出较大值
    '''
    if x > y:
        return x
    else:
        return y

get_max(3, 5)
print(get_max.__doc__) # 输出解释文档的具体内容

Python 3 中的类型注解

Python 是一种高级语言,在我们编写代码的时候,我们定义的变量和定义函数里面的参数的时候,是不用区分它们的类型。 但是作为作者我们知道函数的参数应该传入什么类型的数据,但是作为读者并不能快速知道变量或者参数的类型是什么。 针对上述问题,我们就可以使用类型注解,类型注解的好处就是让读者快速知道我们变量或者参数的类型是什么。

  • 通用写法
    def add(x, y):
      return x + y
    
  • 函数注解写法,表明传入的两个数字是int类型
    def add(x: int, y: int) -> int:
      return x + y
    

命名规范

基本原则:Python 语言的标识符必须以字母、下划线 _ 开头,数字不能作为开头,后面可以跟任意数目的字母、数字和下划线 _。此处的字母并不局限于 26 个英文字母,可以包含中文字符、日文字符等。
禁忌:Python 包含一系列关键字和内置函数,不建议使用它们作为变量名,防止发生冲突。

常用命名规则:
项目名:首字母大写、其余单词小写,多单词组合则用下划线分割
包名、模块名:全用小写字母
类名:首字母大写、其他字母小写,多单词采用驼峰
方法:小写单词
函数:若函数的参数名与保留关键字冲突,则在参数后加一个下划线,比拼音好太多
全局变量:采用全大写,多单词用下划线分割

注意:
不论是类成员变量还是全局变量,均不使用 m 或 g 前缀。
私有类成员使用单一下划线前缀标识,多定义公开成员,少定义私有成员。
变量名不应带有类型信息,因为 Python 是动态类型语言。如 iValue、names_list、dict_obj 等都是不好的命名。
开头、结尾一般为 Python 的自有变量,不要以这种方式命名
以 __ 开头(2 个下划线),是私有实例变量(外部不嫩直接访问),依照情况进行命名。

下划线

一个前导下划线:表示非公有,也叫做保护变量,表示类对象和子类对象自己才能访问这些变量。采用 from somemodulename import * 的方法导入模块时,被保护的变量不会被导入。
一个后缀下划线:为了避免关键字冲突,采用的一种命名方法。
两个前导下划线:私有属性,当命名一个类属性可能引起名称冲突时使用。避免与子类中的属性命名冲突,无法在外部直接访问(名字已经被重整所以访问不到),类对象和子类可以访问(公有方法可以间接访问,使用重整后的名称访问)。
两个前导和后缀下划线:内置的的魔法对象或者属性(有特殊用途),例如 __init__ 或者 __file__。我们不要自己创造类似的名称,只需要使用他们即可。

补充:
私有属性和私有方法使用双前置下划线,私有属性和方法类内部,类的对象和子类可以访问
私有属性和私有方法外部不能直接访问
单前置下划线是普通方法
父类的私有属性和私有方法
子类对象不能在自己的方法内部,直接访问父类的私有属性或私有方法
子类对象可以通过父类的公有方法间接访问到私有属性或私有方法

私有属性本质:
类创建的时候,在 __init__ 方法中,采用双前置下划线创建的属性,该属性创建后,类内部实际上对该属性进行了名字重整(改名了,私有方法和属性在外部不可以直接用属性或方法名调用,内部将私有方法和属性在前面增加了 "_类名")。
因此实例化对象后,外界访问不到,但是使用重整后的名字可以访问。

Python 代码缩进中是否支持 Tab 键和空格混用。

不允许 tab 键和空格键混用,这种现象在使用 sublime 的时候尤为明显。一般推荐使用 4 个空格替代 tab 键

例举几个规范Python代码风格的工具

pylint 和 flake8

例举五条PEP8规范

不要在行尾加分号, 也不要用分号将两条命令放在同一行
不要使用反斜杠连接行
不要在返回语句或条件语句中使用括号
顶级定义之间空2行, 方法定义之间空1行,顶级定义之间空两行
如果一个类不继承自其它类, 就显式的从object继承

单元测试

什么是单元测试 Unit Testing

  • 针对程序模块进行正确性校验
  • 一个函数 一个类进行验证
  • 自底向上保证程序正确性校验

为什么要写单元测试

  • 三无代码不可取 (无文档 无注释 无单元测试)
  • 保证代码逻辑的正确性(甚至有些采用测试驱动开发(TDD))
  • 单元测试影响设计 易测试的代码往往是高内聚低耦合的
  • 回归测试 防止改一处整个服务不可用

单元测试相关的库

  • nose/pytest较为常用
  • mock模块用来模拟替换网络请求等
  • coverage统计测试覆盖率

样例-二分查找单元测试

def binary_search(nums: list, target: int) -> int:
    if not nums:
        return -1
    start, end = 0, len(nums)
    while start < end:
        mid = (start + end) // 2
        # 如果中间值刚好等于目标值,就直接返回中间值索引
        if nums[mid] == target:
            return mid
        # 如果中间值大于目标值 就把结尾值的索引和中间值索引替换
        elif nums[mid] > target:
            end = mid
        # 否侧就是中间值小于目标值 就把起始值的索引替换为中间值索引+1
        else:
            start = mid + 1
    return -1


def test():
    """
    如何设计测试用例: (等价类划分)
    - 正常值功能用例
    - 边界值 (比如最大最小 最左最右)
    - 异常值 (比如None 空值 非法值)
    :return:
    """
    # 正常值 包含有无两种结果
    assert binary_search([0, 1, 2, 3, 4, 5], 3) == 3
    assert binary_search([0, 1, 2, 3, 4, 5], 6) == -1
    assert binary_search([0, 1, 2, 3, 4, 5], -1) == -1
    # 边界值
    assert binary_search([0, 1, 2, 3, 4, 5], 0) == 0
    assert binary_search([0, 1, 2, 3, 4, 5], 5) == 5
    assert binary_search([0], 0) == 0
    # 异常值
    assert binary_search([], 1) == -1

test()