【python】python编码规范

作者: JasonDing | 来源:发表于2015-01-29 21:14 被阅读3728次

    PEP介绍

    PEP是 Python Enhancement Proposal 的缩写,是Python增强建议书的意思。
    Python的代码风格由PEP 8描述。这个文档描述了Python编程风格的方方面面。在遵守这个文档的条件下,不同程序员编写的Python代码可以保持最大程度的相似风格。这样就易于阅读,易于在程序员之间交流。

    命名规则

    不同的命名风格

    有许多不同的命名风格。以下的有助于辨认正在使用的命名风格,这独立于它们的作用。

    • 小写串 (lowercase)
    • 带下划线的小写串 (lower_case_with_underscores)
    • 大写串 (UPPERCASE)
    • 带下划线的大写串 (UPPER_CASE_WITH_UNDERSCORES)
    • 首字母大写单词串 (CapitalizedWords) (或 CapWords、CamelCase,因其字母看起来错落有致,故得此名)
      注意: 在CapWords中使用缩写,需要把缩写的所有字母大写。故HTTPServerError比HttpServerError更好。
    • 混合大小写串 (mixedCase) (与首字母大写串不同之处在于第一个字符是小写的!)
    • 带下划线的首字母大写串 (Capitalized_Words_With_Underscores) (丑陋!)

    避免采用的名字

    决不能使用字母'l'(L的小写字母)、'O'(o的大写字母)、'I'(i的大写字母)) 作为单个字符的变量名。
    在一些字体中,这些字符不能与数字1和0区别开。当想要使用'l'时,用'L'代替它。

    包和模块名(Package and Module Names)

    模块名应该是简短的、全部小写的名字。可以在模块名中使用下划线以提高可读性。Python包名也应该是简短的、全部小写的名字,尽管不推荐使用下划线。
    因为模块名被映射到文件名,有些文件系统大小写不敏感并且截短长名字,所以把 模块名选择为相当短就很重要了——这在Unix上不是问题,但当把代码迁移到Mac、Windows或DOS上时,就可能是个问题了。
    当一个用C或C++写的扩展模块,有一个伴随的Python模块来提供一个更高层(例如,更面向对象)的接口时,C/C++ 模块名有一个前导下划线 (如:_socket)。

    类名(Class Names)

    几乎没有例外,类名使用首字母大写单词串(CapWords)的约定。内部使用的类使用一个额外的前导下划线。

    异常名 (Exception Names)

    因为异常应该是类,故类命名约定也适用于异常。然而,你应该对异常名添加后缀"Error"(如果该异常的确是一个错误)。

    全局变量名(Global Variable Names)

    (我们希望这些变量只打算用于一个模块内部)。
    对设计为通过"from M import "来使用的模块,应采用all机制来防止导出全局变量;或者使用旧的约定,为该类全局变量加一个前导下划线(可能你想表明这些全局变量是只限制在该模块内部使用,"module non-public")。

    补充:
    在python的module中,可以使用 all 函数来定义这个module像其他引用自己的module导入的变量:

    __all__ = ['bar', 'baz']
    waz = 5
    bar = 10
    

    当另一个模块中使用import *声明,waz和bar变量不会被导入,all可以隐藏不想被import的默认值。

    函数名(Function Names)

    函数名应该为小写,必要时可用下划线分隔单词以增加可读性。
    混合大小写 (mixedCase) 仅被允许用于这种风格已经占优势的上下文 (如: threading.py),以便保持向后兼容。

    函数和方法的参数(Function and method arguments)

    对实例的方法,总是用'self'做第一个参数。
    对类的方法,总是用'cls'做第一个参数。
    (如果函数的参数名与保留关键字冲突,在参数名后加一个下划线,比用缩写、错误的拼写要好。因此"print_"比 "prnt"好。也许使用同义词来避免冲突更好)

    补充:
    python的类中,普通方法的第一个参数需要是self,它表示一个具体的实例本身;如果用了staticmethod,那么就可以无视这个self,而将这个方法当成一个普通的函数使用;而对于classmethod,它的第一个参数不是self,是cls,它表示这个类本身。

    >>> class A(object):
            def foo1(self):
                print "Hello",self
            @staticmethod
            def foo2():
                print "hello"
            @classmethod
            def foo3(cls):
                print "hello",cls
    
    >>> a = A()
    >>> a.foo1()          #最常见的调用方式,但与下面的方式相同
    Hello <__main__.A object at 0x9f6abec>
    >>> A.foo1(a)         #这里传入实例a,相当于普通方法的self
    Hello <__main__.A object at 0x9f6abec>
    >>> A.foo2()          #这里,由于静态方法没有参数,故可以不传东西
    hello
    >>> A.foo3()          #这里,由于是类方法,因此,它的第一个参数为类本身。
    hello <class '__main__.A'>
    >>> A                 #可以看到,直接输入A,与上面那种调用返回同样的信息。
    <class '__main__.A'>
    

    方法名和实例变量(Method Names and Instance Variables)

    采用函数命名规则:小写单词,必要时可用下划线分隔单词以增加可读性。
    仅对 non-public 方法和实例变量采用一个前导下划线。

    为避免与子类命名冲突,采用两个前导下划线来触发 Python 的命名重整规则。
    Python用类名重整这些名字:如果类Foo有一个属性名为__a,它不能以Foo.__a访问(执著的用户还是可以通过Foo._Foo__a得到访问权)。通常,双 前导下划线仅被用来避免与基类的属性发生名字冲突。

    谨记python特色的命名惯例

    • 公开属性应该没有前导下划线
    • 如果公开属性名和保留关键字冲突,在你的属性名后添加一个后置下划线
    • 对简单的公开数据属性 (data attribute),最好只暴露属性名,没有复杂的访问/修改方法
      谨记Python为将来增强提供了一条容易的途径,你应该发现简单数据属性需要增加功能行为。在那种情况,用特性(properties)把功能实现隐藏在简单数据属性访问语法后面。
    • 以单一下划线的变量名(_X)不会被from module import *语句导入。一个前导下划线的函数是私有函数。
      Python 中不存在私有变量一说,若是遇到需要保护的变量,使用小写和一个前导下划线。但这只是程序员之间的一个约定,用于警告说明这是一个私有变量,外部类不要去访问它。但实际上,外部类还是可以访问到这个变量。
    • 前后有两个下划线的变量名(X)是系统定义的变量名,对解释器有特殊意义。包括两个前导下划线,两个后置下划线的函数名,这种风格只应用于特殊函数,比如操作符重载等。
    • 以两个下划线开头,但结尾没有两个下划线的变量名(__X)是类的本地变量

    代码布局

    缩进(Indentation)

    每级缩进用 4 个空格。
    绝不要混合使用 tab 和空格。
    最流行的 Python 缩进方式是仅使用空格,其次是仅使用制表符。混合着制表符和空 格缩进的代码将被转换成仅使用空格。调用 Python 命令行解释器时使用 -t 选项, 可对代码中不合法的混用制表符和空格发出警告 (warnings)。使用 -tt 时警告将变 成错误。这些选项是被高度推荐的。
    对新项目,强烈推荐只用空格,而不是用tabs。大多数编辑器拥有使之易于实现的功能。

    最大行宽(Maximum Line Length)

    限制所有行的最大行宽为79字符。
    折叠长行的首选方法是使用Python支持的圆括号、方括号(brackets)和花括号(braces)内的行延续。如果需要,你可以在表达式周围增加一对额外的圆括号,但是有时使用反斜杠看起来更好。确认恰当地缩进了延续的行。

    class Rectangle(Blob): 
        def __init__(self, width, height,  
            color='black', emphasis=None, highlight=0): 
            if width == 0 and height == 0 and \  
                color == 'red' and emphasis == 'strong' or \ highlight > 100:  
                raise ValueError("sorry, you lose")  
            if width == 0 and height == 0 and (color == 'red' or  
                    emphasis is None): 
                raise ValueError("I don't think so")  
            Blob.__init__(self, width, height,  
                        color, emphasis, highlight) 
    

    空行(Blank Lines)

    用两行空行分割顶层函数和类的定义。
    类内方法的定义用单个空行分割。
    在函数中使用空行时,请谨慎的用于表示一个逻辑段落。


    导入 (Imports)

    • 通常应该在单独的行中导入:
      Yes: import os
      import sys

    No: import sys, os
    但是这样也是可以的:
    from subprocess import Popen, PIPE

    • Imports通常被放置在文件的顶部,仅在模块注释和文档字符串之后,在模块的全局变量和常量之前。

    • Imports应该按照如下顺序成组安放:

    1. 标准库的导入
    2. 相关的第三方包的导入
    3. 本地应用/库的特定导入
    • 对于内部包的导入是非常不推荐使用相对导入的。对所有导入总是使用包的绝对路径

    • 从一个包含类的模块中导入类时,通常可以写成这样:
      from myclass import MyClass
      from foo.bar.yourclass import YourClass
      如果这样写导致了本地名字冲突,那么就这样写:
      import myclass
      import foo.bar.yourclass
      并使用"myclass.MyClass" and "foo.bar.yourclass.YourClass"


    在表达式和语句中的空格(Whitespace in Expressions and Statements)

    • 紧挨着圆括号、方括号和花括号:
      Yes: spam(ham[1], {eggs: 2})
      No: spam( ham[ 1 ], { eggs: 2 } )
    • 紧贴在逗号、分号或冒号前:
      Yes: if x == 4: print x, y; x, y = y, x
      No: if x == 4 : print x , y ; x , y = y , x
    • 紧贴着函数调用的参数列表前的开式括号:
      Yes: spam(1)
      No: spam (1)
    • 紧贴在索引或切片 (indexing or slicing) 开始的开式括号前:
      Yes: dct['key'] = lst[index]
      No: dct ['key'] = lst [index]
    • 在赋值 (或其他) 运算符周围的用于和其他语句对齐的一个以上的空格:
      Yes:
      x = 1
      y = 2
      long_variable = 3
      No:
      x = 1
      y = 2
      long_variable = 3

    注释(Comments)

    同代码不一致的注释比没注释更差。当代码修改时,始终优先更新注释!
    注释应该是完整的句子。如果注释是一个短语或句子,首字母应该大写,除非它是一个以小写字母开头的标识符(永远不要修改标识符的大小写)。
    如果注释很短,可以省略末尾的句号。注释块通常由一个或多个段落组成,段落是由完整的句子构成的,每个句子应该以句号结尾。
    你应该在结束语句的句点(a sentence-ending period)后使用两个空格。
    非英语国家的Python程序员:请用英语书写你的注释,除非你120%的确信代码永远不会被不懂你的语言的人阅读。

    注释块(Block Comments)

    注释块通常应用于跟随其后的一些 (或者全部) 代码,并和这些代码有着相同的缩进 层次。注释块中每行以 '#' 和一个空格开始 (除非它是注释内的缩进文本)。
    注释块内的段落以仅含单个 '#' 的行分割。

    行内注释(Inline Comments)

    节俭使用行内注释。
    一个行内注释是和语句在同一行的注释。行内注释应该至少用两个空格和语句分开。 它们应该以一个 '#' 和单个空格开始。
    行内注释不是必需的,事实上,如果说的是显而易见事,还会使人分心。不要这样做 :
    x = x + 1 # Increment x
    但是有时,这样是有益的:
    x = x + 1 # Compensate for border

    参考资料

    如何使用Pylint来规范Python代码风格
    PEP 8 - Style Guide for Python Code

    转载请注明作者Jason Ding及其出处
    Github博客主页(http://jasonding1354.github.io/)
    CSDN博客(http://blog.csdn.net/jasonding1354)
    简书主页(http://www.jianshu.com/users/2bd9b48f6ea8/latest_articles)

    相关文章

      网友评论

      • 676319be8cf3:很详细。
      • wonderay: @tsingcoo
        类方法才能那样用,使用@classmethod定义类方法,按约定,类方法的第一个参数为cls.
      • 094825962fc6:Python3中使用A.foo3()会出现TypeError: foo3() missing 1 required positional argument: 'cls'错误,请问是什么原因,小白求问

      本文标题:【python】python编码规范

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