美文网首页
python编写规范

python编写规范

作者: 日理万机_e6fa | 来源:发表于2020-04-23 09:05 被阅读0次

    一、 说明

    为了规范Python代码的书写,提高代码的可读性,使编码人员在代码上更好的协作,制定了本规范。

    中标软件有限公司测试中心员工在编写Python代码时,必须遵守本规范。如对规范有异议,请联系维护人员。

    编码规范的作用:

    提高可读性 ——“任何一个傻瓜都能写出计算机可以理解的代码,唯有写出人类容易理解的代码,才是优秀的程序员。”编码规范,帮助我们写出人类容易理解的代码。

    统一全局,促进团队协作—— 开发是一个团队活动,而不是个人的英雄主义。

    有助于知识传递,加快工作交接 ——风格的相似性,能让编码人员更迅速,更容易理解一些陌生的代码,更快速地理解别人的代码。

    减少名字增生,降低维护成本 ——在没有规范的情况下,很容易为同一类型的实例起不同的名字。

    强调变量之间的关系,降低缺陷引入的机会 ——命名可以表示一定的逻辑关系,使开发人员在使用时保持警惕,从而一定程度上减少缺陷被引入的机会。

    提高个人能力 。

    二、  内容

    1. 代码布局

    1.1 缩进

    推荐以4个空格作为一个缩进层次。

    1.2 表达式和语句中的空格

    1. 前导空格(缩进)

    最流行的Python缩进方式是仅使用空格,其次是仅使用制表符。对于新的项目,应该仅使用空格而不是制表符。

    2. 非前导空格

    非前导空格在Python代码中没有意义,但适当地加入非前导空格可以增进代码可读性:

    (1)在二元算术、逻辑运算符前后加空格,如:

    示例:

    a = b + c

    if a and b:

        pass

    (2)在一元前缀运算符后不加空格,如:

    示例:

    if !flg:

    pass

    (3)“:”用在行尾时前后皆不加空格,如分支、循环、函数和类定义语言;用在非行尾时后端加空格,如dict对象的定义:

    示例:

    d = {'key': 'value'}

    (4)括号(含圆括号、方括号和花括号)前后不加空格,如:

    示例:

    do_something(arg1, arg2)

    (5)逗号后面加一个空格,前面不加空格。

    1.3 行的最大长度

    每行的最大长度不得超过80个字符的标准。超过80个字符的,建议使用以下方式将单个长行折叠成多个短行:

    (1)为长变量名换一个短名,如:

    错误写法:

    this.is.a.very.long.variable_name = this.is.another.long.variable_name

    正确写法:

    variable_name1 = this.is.a.very.long.variable_name

    variable_name2 = this.is.another.variable_name

    variable_name1 = variable_name2

    (2)在括号(包括圆括号、方括号和花括号)内的分隔符后换行,如:

    示例:

    class Edit(Base):

        def __init__(self, parent, width,

        font = FONT, color = BLACK, pos = POS, style = 0):  # 注意:此行与上一行保持同样缩进

            pass

    (3)在长行加入续行符强行断行,断行的位置应在操作符前,如:

    示例:

    if color == WHITE or color == BLACK \

    or color == BLUE:  # 注意:换行与首行保持同样的缩进(或均不缩进)

        do_something(color)

    1.4 空行

    输入空行时,一般遵循以下原则:

    (1)在import不同种类的模块间加空行;

    (2)顶层函数和类的定义之间加空行;

    (3)在类与类的定义之间加空行;

    (4)在函数与函数的定义之间加空行;

    (5)在class定义行和其第一个方法定义之间加空行;

    (6)在函数中的逻辑段落间加空行,即把相关的代码紧凑写在一起,作为一个逻辑段落,段落间以空行分隔。

    1.5 编码

    所有的Python脚本文件都应在文件头标上#-*- coding:utf8 -*- ;用于设置编辑器,默认保存为utf8格式:

    #-*- coding:utf8 -*-

    2. 语句

    2.1 标准头部

    一般情况下使用如下标准头部语句:

    #!/usr/bin/python

    如果需要使用自定义的Python编译环境,可使用类似如下的头部语句:

    #!/usr/bin/env python2.7

    说明:该行语句的作用是帮助内核找到Python解释器,但通常在Python导入模块时被忽略;只有直接执行单个文件时,该语句才是必要的。

    2.2 导入(import)

    1. 通常应该在单独的行中导入(import),例如“正确写法1”;若需要在一行中从一个模块导入多个类,可参照“正确写法2”:

    错误写法:

    import sys, os

    正确写法1:

    import sys

    import os

    正确写法2:

    from types import StringType, ListType

    2. 导入语句的位置及导入顺序

    通常将import语句放置在文件的顶部,仅在模块注释和文档字符串之后,在模块的全局变量和常量之前。导入语句应该有顺序地成组安放:

    (1)首先,导入标准库(内置模块);

    (2)其次,导入第三方模块(引用的第三方包);

    (3)最后,导入自己开发的项目中的其他模块;

    在每组导入之间放置一个空行。

    3. 导入类的方法

    从一个包含类的模块中导入类时,通常可以写成这样:

    示例:

    from MyClass import MyClass

    from foo.bar.YourClass import YourClass

    如果上述写法导致了本地名字冲突,那么就这样写:

    示例:

    import MyClass

    import foo.bar.YourClass

    然后使用MyClass.MyClass和foo.bar.YourClass.YourClass方式即可。

    2.3 赋值

    对于赋值语言,主要是不要做无谓的对齐,如:

    错误写法:

    a        = 1

    var      = 2

    fn      = callback_function

    正确写法:

    a = 1

    var = 2

    fn = callback_function

    2.4 分支和循环

    各种分支和循环语句不要写成一行,如:

    错误写法:

    if !flg: pass

    for i in xrange(10): print i

    正确写法:

    if !flg:

        pass

    for i in xrange(10):

        print i

    3. 注释

    代码修改时,始终优先更新注释。注释应该是完整的句子,如果注释是一个短语或句子,首字母应该大写,除非他是一个以小写字母开头的标识符(如果以中文注释可忽略此要求)。

    3.1 注释块

    注释块通常用于跟随着一些代码并和这些代码有着相同的缩进层次。注释块中每行均以“#”和一个空格开始。注释块内的段落间以仅含单个“#”的行分割。注释块上下方最好各有一空行。

    3.2 行内注释

    行内注释是和语句在同一行的注释。行内注释应该至少用两个空格和语句分开,且应该以“#”和单个空格开始,如:

    示例:

    x = x + 1  # Increment x

    如果语意很明了,那么行内注释则不必要。

    3.3 文档字符串

    为所有公共模块、函数、类和方法编写文档字符串。文档字符串对非公开的方法不是必要的,但应该有一个注释描述这个方法的作用。这个注释应该在“def”行之后。

    一定注意,多行文档字符串结尾的"""应该单独成行,例如:

    示例:

    """Return a foobang

    Optional plotz says to frobnicate the bizbaz first

    """

    对单行的文档字符串,结尾的"""在同一行也可以,例如:

    """Return a foobang"""

    3.4 版本注记

    版本注记可以参照如下示例代码:

    示例:

    __version__ = "$Revision: 1.4 $"

    这行应该包含在模块的文档字符串之后,所有代码之前,上下用一个空行分割。

    3.5 模块注释

    每个模块注释都应该包含下列项,依次是:

    (1)版权声明;

    (2)模块注释内容,包括模块描述、模块中的类和方法的描述、版本及维护信息等;

    (3)作者声明,标识文件的原作者;

    示例:

    # Copyright (C), 2010-2013, China Standard Software Co., Ltd.

    """

    FileName: Test.py

    Author: fei.liu

    Version: 0.1

    Date: 2013-02-27

    Description: 用一行文字概述模块或脚本,用句号结尾。

        ClassFoo: 一行概述该模块中的类的用途。

        functionBar(): 一行概述该模块中的函数的用途。

    History: /* 历史修改记录 */

    <Author>  <Date>  <Version>  <Desc>

    fei.liu  2013-03-04  1.0      Release

    """

    __authors__ = [

      '"John Smith" <johnsmith@example.com>',

      '"Joe Paranoid" <joeisgone@example.com>',

    ]

    3.6 函数和方法注释

    任何函数或方法都需要一个文档字符串,对于任何外部可访问的函数或方法,文档字符串尤为重要。

    文档字符串应该包含函数的作用,以及参数、输入和输出的详细描述:

    (1)Args:输入参数的具体描述;如果参数要求特定的数据类型或者设置了参数的默认值,那么应该在文档字符串中明确说明;

    (2)Returns:输出(返回)数据的具体描述;

    (3)Raises:应该列出该函数可能触发的所有异常;

    示例:

    def fetch_bigtable_rows(big_table, keys, other_silly_variable=None):

        """取出表格中的多行内容

        Retrieves rows pertaining to the given keys from the Table instance

        represented by big_table.  Silly things may happen if

        other_silly_variable is not None.

        Args:

            big_table: An open Bigtable Table instance.

            keys: A sequence of strings representing the key of each table rowto fetch.

            other_silly_variable: Another optional variable, that has a much

                longer name than the other args, and which does nothing.

        Returns:

            A dict mapping keys to the corresponding table row data fetched.

    Each row is represented as a tuple of strings. For example:

            {'Serak': ('Rigel VII', 'Preparer'),

            'Zim': ('Irk', 'Invader'),

            'Lrrr': ('Omicron Persei 8', 'Emperor')}

            If a key from the keys argument is missing from the dictionary,

            then that row was not found in the table.

        Raises:

            IOError: An error occurred accessing the bigtable.Table object.

        """

        pass

    3.7 类注释

    类定义下方必须有一个用于描述该类的文档字符串(docString)。如果类中有公共属性(Attributes),那么文档字符串中应该说明这些公共属性的意义。

    示例:

    class SampleClass(object):

        """Summary of class here.

        Longer class information....

        Longer class information....

        Attributes:

            likes_spam: A boolean indicating if we like SPAM or not.

            eggs: An integer count of the eggs we have laid.

        """

        def __init__(self, likes_spam=False):

            """Inits SampleClass with blah."""

            self.likes_spam = likes_spam

            self.eggs = 0

        def public_method(self):

            """Performs operation blah."""

    4. 命名约定

    4.1 说明:命名约定

    禁止使用字符“l”、“O”或“I”作为单字符的变量名。在某些字体中无法将这些字符与数字1和0区分开。

    4.2 模块名

    模块名应该是不含下划线的、简短的、全小写的名字;对于默认仅在包(Packages)内使用的模块,可以加一个下划线前缀,如:

    示例:

    module.py

    _internal_module.py

    4.4 类名

    类名使用CapWords约定(单词首字母大写,不使用下划线连接单词,也不加入C、T等前缀);内部使用的类需要在名称前加一个前导下划线,如:

    示例:

    class ThisIsAClass(object):

    pass

    class _ThisIsAClass(object):

    pass

    4.5 异常名

    异常名使用CapWords命名规则(单词首字母大写,不使用下划线连接单词)。

    4.6 变量、常量、全局变量名

    Python一般通过“from M import *”来从模块中导入相关内容(变量、类、函数等),必须用一个下划线作全局变量(内部函数或类)的前缀防止其被导出(exporting)。

    1. 常量

    常量名的所有字母均大写,由下划线连接各个单词,如:

    示例:

    WHITE = 0XFFFFFF

    THIS_IS_A_CONSTANT = 1

    2. 变量

    (1)变量名全部小写,由下划线连接各个单词,如:

    示例:

    color = WHITE

    this_is_a_variable = 1

    (2)不论是类成员变量还是全局变量,均不使用m或g前缀。私有类成员使用单一下划线前缀标识;

    (3)变量名不应带有类型信息,因为Python是动态类型语言;如iValue、names_list、dict_obj等都是不好的命名。

    3. 全局变量

    必须用一个下划线作为全局变量的前缀防止其被导出。

    4.7 函数名

    函数名应该为小写,可用下划线风格单词以增加可读性。

    4.8 方法名和实例变量

    大体上和函数命名规则相同:通常使用小写单词,必要时用下划线分隔增加可读性。

    如果是不打算对外公开的内部方法和实例,需要在名称开头使用一个前导下划线。

    使用两个前导下划线以表示类私有成员的名字。通常双前导下划线仅被用于避免含子类的类中的属性名冲突。

    4.9 特定的命名方式

    主要是指__xxx__形式的系统保留字命名法。项目中也可以使用这种命名,它的意义在于这种形式的变量是只读的,这种形式的类成员函数尽量不要重载。如:

    示例:

    class Base(object):

        def __init__(self, id, parent = None):

            self.__id__ = id

            self.__parent__ = parent

        def __message__(self, msgid):

            # ...

    其中__id_、__parent__和__message__都采用了系统保留字命名法。

    5. 继承的设计

    始终要确定一个类中的方法和实例变量是否要被公开。通常,永远不要将数据变量公开,除非你实现的本质上只是记录,人们总是更喜欢为类提供一个函数的接口来实现数据变量的修改。

    同样,确定你的属性是否应为私有的。私有和非私有的区别在于:前者永远不会被用在一个派生类中,而后者可能会。你应该在大脑中就用继承设计好了你的类:(1)私有属性必须有两个前导下划线,无后置下划线;(2)非公有属性必须有一个前导下划线,无后置下划线;(3)公共属性没有前导和后置下划线,除非它们与保留字冲突,在此情况下,单个后置下划线比前置或混乱的拼写要好,例如:class_优于klass。

    6. 设计建议

    单个元素(singletons)的比较,如None应该使用“is”或“is not”。当你本意是“if x is not None”时,对写成“if x”要小心。例如当你测试一个默认为None的变量或参数是否被设置为其它值时,这个其它值也许在布尔上下文(Boolean context)中是False。

    基于类的异常总是好过基于字符串的异常。模块和包应该定义它们自己的域内特定的基异常类,基类应该是内建的Exception类的子类,还始终包含一个类的文档字符串。例如:

    示例:

    #!/usr/bin/Python

    class(Exception):

    """Base class for errors in the email package."""

    MessageError

    使用字符串方法(methods)代替字符串模块,除非必须向后兼容Python 2.0以前的版本。字符串方法总是非常快,而且和unicode字符串共用同样的API(应用程序接口),在检查前缀或后缀时避免对字符串进行切片。用startswith()和endswith()代替,因为这样出现错误的机率更小。例如:

    错误写法:

    if foo[:3] == 'bar':

    正确写法:

    if foo.startswith('bar'):

    特殊情况下,如果你的代码必须工作在Python 1.5.2,对象类型的比较应该始终用isinstance()代替直接比较类型,例如:

    错误写法:

    if type(obj) is type(1):

    正确写法:

    if isinstance(obj, int):

    检查一个对象是否是字符串时,谨记它也可能是unicode字符串!在Python 2.3中,str和unicode有公共的基类basestring,所以你可以这样做:

    if isinstance(obj, basestring):

    在Python 2.2类型模块为此定义了StringTypes类型,例如:

    #!/usr/bin/Python

    from types import StringTypes

    if isinstance(obj, StringTypes):

    对序列(字符串、列表、元组)而言,使用空列表是false这个事实,因此“if not seq”或“if seq”比“if len(seq)”或“if not len(seq)”好。书写字符串文字时不要依赖于有意义的后置空格。这种后置空格在视觉上是不可辨别的,并且有些编辑器会将它们修整掉。不要用“==”来比较布尔型的值以确定是True或False(布尔型是Python2.3中新增的):

    错误写法:

    if greeting == True:

    正确写法:

    if greeting:

    相关文章

      网友评论

          本文标题:python编写规范

          本文链接:https://www.haomeiwen.com/subject/pdgiihtx.html