Python代码这样写才规范优雅! (三)

浏览: 2153

前文传送门:

Python代码这样写才规范优雅! (一)

Python代码这样写才规范优雅! (二)

参考:

https://www.python.org/dev/peps/pep-0008/

Python PEP8编码规范的内容如下:

1. Introduction 介绍
2. A Foolish Consistency is the Hobgoblin of Little Minds 尽信书,则不如无书
3. Code lay-out 代码布局
3.1 Indentation 缩进
3.2 Tabs or Spaces? 制表符还是空格?
3.3 Maximum Line Length 行的最大长度
3.4 Should a line break before or after a binary operator? 在二元运算符之前应该换行吗?
3.5 Blank Lines 空行
3.6 Source File Encoding 源文件编码
3.7 Imports 导入
3.8 Module level dunder names 模块级的“呆”名
4. String Quotes 字符串引号
5. Whitespace in Expressions and Statements 表达式和语句中的空格
5.1 Pet Peeves 不能忍受的事情
5.2 Other Recommendations 其他建议
6. Comments 注释
6.1 Block Comments 块注释
6.2 Inline Comments 行内注释
6.3 Documentation Strings 文档字符串
7. Naming Conventions 命名规范
7.1 Overriding Principle 最重要的原则
7.2 Descriptive: Naming Styles 描述:命名风格
7.3 Prescriptive: Naming Conventions 约定俗成:命名约定
7.4 Public and internal interfaces 公共和内部的接口
8. Programming Recommendations 编程建议
8.1 Function Annotations 功能注释
9. 参考

我们接着上一篇的内容继续看:

6. Comments 注释

与代码相矛盾的注释比没有注释还糟,当代码更改时,优先更新对应的注释! 注释应该是完整的句子。如果一个注释是一个短语或句子,它的第一个单词应该大写,除非它是以小写字母开头的标识符(永远不要改变标识符的大小写!)。 如果注释很短,结尾的句号可以省略。块注释一般由完整句子的一个或多个段落组成,并且每句话结束有个句号。 在句尾结束的时候应该使用两个空格。 当用英文书写时,遵循Strunk and White (译注:《Strunk and White, The Elements of Style》)的书写风格。 在非英语国家的Python程序员,请使用英文写注释,除非你120%的确信你的代码不会被使用其他语言的人阅读。

6.1 Block Comments 块注释

块注释通常适用于跟随它们的某些(或全部)代码,并缩进到与代码相同的级别。块注释的每一行开头使用一个#和一个空格(除非块注释内部缩进文本)。 块注释内部的段落通过只有一个#的空行分隔。

6.2 Inline Comments 行内注释

有节制地使用行内注释。 行内注释是与代码语句同行的注释。行内注释和代码至少要有两个空格分隔。注释由#和一个空格开始。 事实上,如果状态明显的话,行内注释是不必要的,反而会分散注意力。比如说下面这样就不需要:

x = x + 1                 # Increment x

但有时,这样做很有用:

x = x + 1                 # Compensate for border

6.3 Documentation Strings 文档字符串

编写好的文档说明(也叫“docstrings”)的约定在PEP257中永恒不变。要为所有的公共模块,函数,类以及方法编写文档说明。非公共的方法没有必要,但是应该有一个描述方法具体作用的注释。这个注释应该在def那一行之后。PEP257 描述了写出好的文档说明相关的约定。特别需要注意的是,多行文档说明使用的结尾三引号应该自成一行,例如:

"""Return a foobang

Optional plotz says to frobnicate the bizbaz first.
"""

对于单行的文档说明,尾部的三引号应该和文档在同一行。

7. Naming Conventions 命名规范

Python库的命名规范很乱,从来没能做到完全一致。但是目前有一些推荐的命名标准。新的模块和包(包括第三方框架)应该用这套标准,但当一个已有库采用了不同的风格,推荐保持内部一致性。

7.1 Overriding Principle 最重要的原则

那些暴露给用户的API接口的命名,应该遵循反映使用场景而不是实现的原则。

7.2 Descriptive: Naming Styles 描述:命名风格

有许多不同的命名风格。这里能够帮助大家识别正在使用什么样的命名风格,而不考虑他们为什么使用。 以下是常见的命名方式:

  • b(单个小写字母)
  • B(单个大写字母)
  • lowercase 小写字母
  • lower_case_with_underscores 使用下划线分隔的小写字母
  • UPPERCASE 大写字母
  • UPPER_CASE_WITH_UNDERSCORES 使用下划线分隔的大写字母
  • CapitalizedWords(或者叫 CapWords,或者叫CamelCase 驼峰命名法 —— 这么命名是因为字母看上去有起伏的外观)。有时候也被称为StudlyCaps。
  • 注意:当在首字母大写的风格中用到缩写时,所有缩写的字母用大写,因此,HTTPServerError 比 HttpServerError 好。
  • mixedCase(不同于首字母大写,第一个单词的首字母小写)
  • Capitalized_Words_With_Underscores(巨丑无比!)

也有用唯一的短前缀把相关命名组织在一起的方法。这在Python中不常用,但还是提一下。比如,os.stat()函数中包含类似以st_mode,st_size,st_mtime这种传统命名方式命名的变量。(这么做是为了与 POSIX 系统的调用一致,以帮助程序员熟悉它。) X11库的所有公共函数都加了前缀X。在Python里面没必要这么做,因为属性和方法在调用的时候都会用类名做前缀,函数名用模块名做前缀。 另外,下面这种用前缀或结尾下划线的特殊格式是被认可的(通常和一些约定相结合):

  • _single_leading_underscore:(单下划线开头)弱“内部使用”指示器。比如 from M import * 是不会导入以下划线开始的对象的。
  • single_trailing_underscore_:(单下划线结尾)这是避免和Python内部关键词冲突的一种约定,比如:Tkinter.Toplevel(master, class_=’ClassName’)
  • __double_leading_underscore:(双下划线开头)当这样命名一个类的属性时,调用它的时候名字会做矫正(在类FooBar中,__boo变成了_FooBar__boo;见下文)。
  • __double_leading_and_trailing_underscore__:(双下划线开头,双下划线结尾)“magic”对象或者存在于用户控制的命名空间内的属性,例如:__init__,__import__或者__file__。除了作为文档之外,永远不要命这样的名。

7.3 Prescriptive: Naming Conventions 约定俗成:命名约定

7.3.1 Names to Avoid 应避免的名字

永远不要使用字母‘l’(小写的L),‘O’(大写的O),或者‘I’(大写的I)作为单字符变量名。 在有些字体里,这些字符无法和数字0和1区分,如果想用‘l’,用‘L’代替。

7.3.2 Package and Module Names 包名和模块名

模块应该用简短全小写的名字,如果为了提升可读性,下划线也是可以用的。Python包名也应该使用简短全小写的名字,但不建议用下划线。 当使用C或者C++编写了一个依赖于提供高级(更面向对象)接口的Python模块的扩展模块,这个C/C++模块需要一个下划线前缀(例如:_socket)

7.3.3 Class Names 类名

类名一般使用首字母大写的约定。 在接口被文档化并且主要被用于调用的情况下,可以使用函数的命名风格代替。 注意,对于内置的变量命名有一个单独的约定:大部分内置变量是单个单词(或者两个单词连接在一起),首字母大写的命名法只用于异常名或者内部的常量。

7.3.4 Exception Names 异常名

因为异常一般都是类,所有类的命名方法在这里也适用。然而,你需要在异常名后面加上“Error”后缀(如果异常确实是一个错误)。

7.3.5 Global Variable Names 全局变量名

(我们希望这一类变量只在模块内部使用。)约定和函数命名规则一样。 通过 from M import * 导入的模块应该使用all机制去防止内部的接口对外暴露,或者使用在全局变量前加下划线的方式(表明这些全局变量是模块内非公有)。

7.3.6 Function Names 函数名

函数名应该小写,如果想提高可读性可以用下划线分隔。 大小写混合仅在为了兼容原来主要以大小写混合风格的情况下使用(比如 threading.py),保持向后兼容性。7.3.7 Function and method arguments 函数和方法参数

始终要将 self 作为实例方法的的第一个参数。 始终要将 cls 作为类静态方法的第一个参数。如果函数的参数名和已有的关键词冲突,在最后加单一下划线比缩写或随意拼写更好。因此 class_ 比 clss 更好。(也许最好用同义词来避免这种冲突)

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

遵循这样的函数命名规则:使用下划线分隔小写单词以提高可读性。 在非共有方法和实例变量前使用单下划线。 通过双下划线前缀触发Python的命名转换规则来避免和子类的命名冲突。 Python通过类名对这些命名进行转换:如果类 Foo 有一个叫 __a 的成员变量, 它无法通过 Foo.__a 访问。(执着的用户可以通过 Foo._Foo__a 访问。)一般来说,前缀双下划线用来避免类中的属性命名与子类冲突的情况。 注意:关于__names的用法存在争论(见下文)。

7.3.9 Constants 常量

常量通常定义在模块级,通过下划线分隔的全大写字母命名。例如:MAX_OVERFLOW 和 TOTAL。

7.3.10 Designing for inheritance 继承的设计

始终要考虑到一个类的方法和实例变量(统称:属性)应该是共有还是非共有。如果存在疑问,那就选非共有;因为将一个非共有变量转为共有比反过来更容易。 公共属性是那些与类无关的客户使用的属性,并承诺避免向后不兼容的更改。非共有属性是那些不打算让第三方使用的属性;你不需要承诺非共有属性不会被修改或被删除。 我们不使用“私有(private)”这个说法,是因为在Python中目前还没有真正的私有属性(为了避免大量不必要的常规工作)。 另一种属性作为子类API的一部分(在其他语言中通常被称为“protected”)。有些类是专为继承设计的,用来扩展或者修改类的一部分行为。当设计这样的类时,要谨慎决定哪些属性时公开的,哪些是作为子类的API,哪些只能在基类中使用。 贯彻这样的思想,一下是一些让代码Pythonic的准则:

  • 公共属性不应该有前缀下划线。
  • 如果公共属性名和关键字冲突,在属性名之后增加一个下划线。这比缩写和随意拼写好很多。(然而,尽管有这样的规则,在作为参数或者变量时,‘cls’是表示‘类’最好的选择,特别是作为类方法的第一个参数。)注意1:参考之前的类方法参数命名建议
  • 对于单一的共有属性数据,最好直接对外暴露它的变量名,而不是通过负责的 存取器(accessor)/突变(mutator) 方法。请记住,如果你发现一个简单的属性需要成长为一个功能行为,那么Python为这种将来会出现的扩展提供了一个简单的途径。在这种情况下,使用属性去隐藏属性数据访问背后的逻辑。注意1:属性只在new-style类中起作用。 注意2:尽管功能方法对于类似缓存的负面影响比较小,但还是要尽量避免。 注意3:属性标记会让调用者认为开销(相当的)小,避免用属性做开销大的计算。
  • 如果你的类打算用来继承的话,并且这个类里有不希望子类使用的属性,就要考虑使用双下划线前缀并且没有后缀下划线的命名方式。这会调用Python的命名转换算法,将类的名字加入到属性名里。这样做可以帮助避免在子类中不小心包含了相同的属性名而产生的冲突。注意1:只有类名才会整合进属性名,如果子类的属性名和类名和父类都相同,那么你还是会有命名冲突的问题。 注意2:命名转换会在某些场景使用起来不太方便,例如调试,__getattr__()。然而命名转换的算法有很好的文档说明并且很好操作。 注意3:不是所有人都喜欢命名转换。尽量避免意外的名字冲突和潜在的高级调用。

7.4 Public and internal interfaces 公共和内部的接口

任何向后兼容保证只适用于公共接口,因此,用户清晰地区分公共接口和内部接口非常重要。 文档化的接口被认为是公开的,除非文档明确声明它们是临时或内部接口,不受通常的向后兼容性保证。所有未记录的接口都应该是内部的。 为了更好地支持内省(introspection),模块应该使用__all__属性显式地在它们的公共API中声明名称。将__all__设置为空列表表示模块没有公共API。 即使通过__all__设置过,内部接口(包,模块,类,方法,属性或其他名字)依然需要单个下划线前缀。 如果一个命名空间(包,模块,类)被认为是内部的,那么包含它的接口也应该被认为是内部的。 导入的名称应该始终被视作是一个实现的细节。其他模块必须不能间接访问这样的名称,除非它是包含它的模块中有明确的文档说明的API,例如 os.path 或者是一个包里从子模块公开函数接口的 __init__ 模块。

扫码下图关注我们不会让你失望!

image.png

推荐 0
本文由 ID王大伟 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

0 个评论

要回复文章请先登录注册