第六章 python杂货铺之PEP8语法规范

第三章: python语法规范--F

1.python中语法规范标准:

​ PEP8: 编码规范

​ PEP20: python之禅 //import this

​ PEP257: 文档字符串语法规范

2 代码布局规范

2.1缩进规范

​ 不同层次的代码必须要采用缩进进行标识,缩进标准是四个空格;

2.1.1 不同级别的代码缩进规范:

缩进字符说明:

​ case1: 空格是首选的缩进字符,tab也可以作为缩进字符;

​ case2: python3中严禁混合使用space tab作为缩进字符;

​ case3: python2中可以混合使用space tab作为缩进字符;

​ case4:在命令行上,采用-t选项可以检查代码文件中是否采用混合的缩进符号,一旦检查到采用了混合的缩进方式则产生警告信息;-tt选项则是一旦检查到了混合的缩进方式,则直接产生错误;

扩展说明:

​ 在linux系统上,一旦采用了混合的缩进方式,则程序是无法正常启动的;

2.1.2 续行缩进规范

​ 一行长代码续航之后两种缩进类型:

垂直缩进:

​ 续行符号包裹的元素垂直对齐;其中续行时要续多个行,不推荐仅仅续一行;

悬挂缩进:

​ 续行符号的起始字符作为此行的结尾,然后续行符号的内容作为一个或多个新行,其中这多个新行的缩进取决于新的代码层的行的缩进,续行的缩进标准必须要与新的代码行进行区分,推荐的缩进标准是8个空格,或2个tab,这样可以与此行的下层代码做区分;

说明:

​ 垂直缩进的续行符号的开始字符并不是作为该行的结尾字符,续的新行的内容的对齐方式与续航符号的开始字符中的内容垂直对齐;

​ 悬挂缩进的续航符号的开始字符作为该行的结尾字符,续的多个新行采用8个空格进行缩进;续行符号的结尾字符,可以在内容的结尾处存在,也可单独在一个新行的第一个字符,或者在单独一个新行与续行的内容对齐的位置处;

\# 垂直缩进

​        foo = long_function_name(var_one, var_two,

​                                 var_three, var_four)

​        \# 悬挂缩进

​        def long_function_name(

​                var_one, var_two, var_three,

​                var_four):

​        \# 悬挂缩进

​        def long_function_name(

​                var_one, var_two, var_three,

​                var_four

​                ):       

2.2 续行规范

2.2.1 续行符号的类型

​ case1:括号: () [] {} 主要包含圆括号 方括号 花括号三种;

​ case2:三引号: '''xxx''' """ xxx """

​ case3:反斜杠: \

2.2.2 续行符号的区别

​ case1: 三引号: 三引号主要用于定义文档字符串即对象的单行或多行注释信息,即对象的__doc__属性;或同单引号、双引号一样定义字符串,但是三引号用于定义跨越多行的字符串;

​ case2:括号有在不同的代码中有不同的功能,括号有隐式的续行功能,其用于将一行过长的代码多行展示,如:可以用于将if语句的多个条件采用括号括起来做续行,然后设置垂直缩进或悬挂缩进;

​ case3: 反斜杠属于显示的换行符号,其作为一行的最后一个字符其后不能接任何符号,尤其是空格;

说明:

​ 在实现续行时,优先采用括号做续行,若括号不能实现则采用反斜杠,如多个with ..as 语句不能采用括号续行;三引号仅仅只能应用与过长的字符串续行;

2.3 引号规范

2.3.1 引号的类型:

​ case1: 单引号

​ case2: 双引号

​ case3: 三引号

2.3.2 不同引号的功能和区别:

​ case1: 单引号和双引号功能完全相同,其用于定义单行的字符串,字符串的内容不能跨越多行,否则语法错误;

​ case2: 三引号主要用于定义单行或多行注释或定义文档字符串,单行注释也可以采用#进行定义;而三引号自带的隐式续行功能还可以定义跨越多行的字符串然后赋值给一个变量;

引号使用的注意点:

​ case1: 若一个字符串内,本身就包含了引号,那么定义字符串时字符串外层的引号必定要定义成与字符串内类型不同的引号,否则会导致python错误的处理机制造成语法错误;

案列:

​ name='hello 'the fuck' world '

案列说明:

​ 对于此种字符串的定义,python的解释器会将:'hello '识别为一个字符串,而其后的内容单独处理,这样势必造成语法错误;

​ 上述案列中处理在外层采用不同的引号解决之外,还可以将内层的引号采用反斜杠做转义;推荐的方法是在外层采用不同的引号,用以避免采用反斜杠;

2.4.最大行长

​ case1: python中定义了单行最大行长79个字符,单行文档字符串或注释则最大72个字符;python标准库中严格采用此规范;

​ case2: 在开发人员开发的程序中,最大行长可以根据需要设置,但是单行文档字符串和注释最大仍然是72个字符,由__doc__属性决定了此限制;

2.5.文档字符串规范---PEP257

定义:

​ 文件、module、函数、class的首个三个引号内定义的字符串为文档字符串;而此后其他位置采用三引号定义的字符串则为附加文档字符串;

​ 文档字符串其实质就是一个三个引号定义的一个对象的注释信息,这个字符串可以是单行字符串也可以是多行字符串;

​ 文档字符串定义在module 函数 class的第一个非#开头的代码行,定义之后就称为这个对象的__doc__属性,附加文档字符串不会被赋值给__doc__属性;

注意:

​ 文档字符串后的注释行,无论其出现在什么位置,均不再被解释器所识别,这些注释行称之为附加文档字符串;

2.5.1 单行文档字符串特点:

case1: 文档字符串前后并没有空行;

case2: 文档字符串的内容应该定义为'''do this return that''',即说明对象的功能;

2.5.2 多行文档字符串特点:

case1: 多行文档字符串由:三个引号字符和摘要内容作为一个独立行 + 空行 + 详细描述内容 + 三个引号 构成;

case2: 摘要行作为一个总的描述信息,而详细的描述则是说明某个代码的具体信息;

对象为程序文件: 详细信息则是说明该程序的使用方法;

​ 对象为module: 详细信息则是列出模块所包含的类 异常 函数等等信息;

​ 对象为class: 详细信息则是列出公共方法,实例变量等等;

​ 案列:

​ """Return a foobang

​ Optional plotz says to frobnicate the bizbaz first.

​ """

重要说明:

​ 文档字符串、附加文档字符串,均是python中有意义的功能性代码,其会被python的解释器处理,故此其缩进也是完全遵守以上缩进规范的;

2.6 二元运算符规范

说明:

​ 续行时,python接受从二元运算符之前或之后进行 行中断操作然后续行;

​ 推荐采用在二元运算符之前进行行中断续行操作;

案列:

​ income = (gross_wages

​ + taxable_interest

​ + (dividends - qualified_dividends)

​ - ira_deduction

​ - student_loan_interest)

2.7.空行规范

​ case1: 定义函数、类时,其首尾分别采用两个空行与其他代码隔开;

​ case2: 类里的方法定义时,在方法定义的首部采用一个空行隔开;

​ //其他的空行规则不用了解;

2.8.编码格式规范

编码格式的类型:

ASCII码:

万国码--unicode:

utf-8:

gbk/gb2312:

python2和python3的区别:

​ case1: python2采用ascii码进行编码,故此python2仅能识别英文字符; 一旦有其他语言的字符则会导致乱码问题;

​ case2: python3内部实现了unicode,默认编码方式为utf-8;含义为: python解释器加载到内存空间中的所有数据都是unicode编码的字符串或字节码,而内存中的unicode字符存储在存储设备上火进行网络传输时均转换为utf-8编码方式;

说明:

​ 由于除ascii编码之外的所有的编码格式,均是从unicode编码的基础压缩而来,故此unicode编码能够与其他所有类型的字符编码进行互相转换;故此在python3中任意一种类型的编码方式写的文件加载到内存中后能成功转换为unicode,在采用其他的编码方式进行读时又能成功将unicode转换为对应读格式的编码方式;故此python3永不乱码;

2.9.import导入模块规范

​ case1: 多个模块导入采用多行import导入,即一行仅仅导入一个模块;

​ case2: import导入代码应该放置在文件的起始的注释或文档字符串之后,全局变量、常量之前;

​ case2: 避免通配符导入:from xxx import *;

​ case4: 导入模块时,导入的次序为:标准库、第三方库、自定义库;

2.10 __变量名__规范

说明:

​ 双下划线开头和双下划线结尾的变量,应该定义在文件的起始处注释、文档字符串、以及from xx import 语句之后,其余import语句之前即其他的所有的代码之前;

2.11.空格规范

以下情况禁止使用空格:

case1: 括号(圆括号、方括号、花括号)内的字符,与括号字符(括号的开始字符和结束字符)之间不应该有空格;

case2:逗号、分号、冒号之间不应该有空格;

case3: 冒号在切片操作时,应该将冒号当成优先级最低的二元运算符进行处理,冒号左右两侧应该有相同数量的空格;除非冒号一侧的参数省略,空格可以不用遵守这个规范;

case4: 在函数调用语句 索引切片操作的,括号的起始字符的左侧不应该有空格;

case5: 禁止在行尾加空格以及反斜杠后面加空格;

case6: 在函数关键字传参,定义默认参数时,赋值符号左右两侧不要加空格

以下情况使用空格:

case1: 二元运算符左右两侧建议采用空格,如赋值运算、关系运算、比较运算、逻辑运算等;

case2: 在相同类型的复杂运算表达式中,建议将优先级最低的运算符左右两侧加上空格,而其它较高优先级的运算符的左右两侧不要加空格;此种情况也适用于上述二元运算符;

2.12.多行代码规范

复合语句说明:

所谓复合语句,即是将多行的python代码采用一行进行表示;多行代码之间采用分号进行分隔,分号用于标识代码的结束;

case1: 复合语句通常是不符合规范的,但是针对于简单的程序代码,如:if/for/while语句将多行采用复合语句一行表示是没有问题的;

case2: 针对有多个代码块的程序,严禁使用复合语句;

2.13.注释

分类:

​ 行注释 块注释 行内注释

case1: 行注释

行注释应该保证注释与行代码的含义不能相矛盾,行注释可以是一个短语或一个句子,行注释第一个字符应该大写,若行首为一个标识符则要保持和标识符完全相同;

若行注释很短,注释结尾的句号可以省略,若行注释是一个句子则结尾应该采用句号,且句号后应该有两个空格;

case2: 块注释

块注释一般用于非常适用于跟随他们的某些代码,块注释的每一行采用一个#和一个空格开头,块注释内部的段落通过只有一个#的空行分隔;

case2: 行内注释

行内注释是与代码在同一行的注释,行内注释与代码至少要采用两个空格进行分隔,同时行内注释采用一个#和一个空格进行分隔;

扩展说明:---注释与文档字符串的不同

相同:

注释和文档字符串均可以用于做注释,定义或者说明特定代码或代码段的含义;

不同:

case1: 语法不同,注释采用#开头; 而文档字符串则是采用三引号进行标识;

case2: 意义不通,注释仅仅用于说明信息,而文档字符串,则会被赋值给对象的__doc__属性;

case3:除了文件、模块、class、函数的起始文档字符串行会被识别为文档字符串赋值给__doc__之外,其他任意位置的文档字符串仅仅被识别为附加文档字串,不会赋值给__doc__属性;

case4: 文档字符串:无论是文档字符串还是附加文档字符串,其均会被解释器所处理;而注释则直接被解释器忽略不会被处理;

2.14 命名规范;

1 命名规则

case1: 变量名由数字、字母(大小写字母,中文字符均可)、下划线构成,其中数字不能作为变量名的开头;

case2: 变量名不能与系统内置关键字、函数名、类名相同,若相同可以在名称后面加一个下划线;

case3: 变量名内不能包含空格;

case4: 变量名应该尽量简单并且有意义;

2 命名风格:

​ 推荐使用: 下划线连接的多个单词构成的变量名,如:get_ip

​ 不推荐使用: 驼峰式命名风格--多个单词连续在一起每个单词的首字母大小

3 特殊的变量名的意义

_name: 单下划线开头

​ 定义在全局代码中:

​ 此种命名的变量为 内部变量或内部函数;

​ 此种变量或函数,采用import moudle导入时,这些单下划线开头的变量或函数并不会被导入,故此无法被调用到;只能采用from module import _name进行显示的导入,才能被调用到;

​ 定义在class中:

​ 标识该属性为私有属性,python约定单下划线开头的属性一般仅仅在class的内部使用,不应该在class的外部使用,这仅仅是一种约定,在class的外部仍然可以调用到;

name_: 单下划线结尾

​ 变量的命名规范中明确的说明了,变量的命名应该有意义,但是一旦一个变量的命名与python的关键字相同了就会导致变量的定义覆盖解释器的关键字,

​ 此时的解决方法就是将变量的名称后加一个下划线,在保证变量的名称保留了意义的同时,避免了与解释器的关键字冲突的问题;

__name: 双下划线开头

​ 仅仅用于在class中,定义私有属性;

​ 双下划线开头的属性,仅仅只能在当前类内部使用,在当前class的内部调用,仍然采用定义时的变量名进行调用即可;

​ 而一旦在子类或class的外部进行调用,是无法直接被调用的;双下划线定义的属性,解释器的底层代码会将其重命名之后存放在class的属性字典当中,命名规则:'_类名__name';通过重命名后的属性名称在子类或class外部进行调用;

_name_: 双下划线开头和双下划线结尾

​ 此种变量,为系统预定义的变量或class的内置属性,用户的程序代码中不应该采用此种命名方式

_: 独立的下划线

​ 独立的下划线也可以作为一个变量名,此变量仅仅用作一个临时变量,在程序的代码执行过程中此变量的值随时会发生变化;

​ _独立的下划线变量,存储的最近一次表达式的执行结果的值,故此程序在运行过程中这个值会不断发生变化;需要注意的是_存储的表达式的最近一个表达式的结果,而非最近的代码的执行结果;

​ 表达式一般用于做运算(算术 逻辑 关系 比较 判断等),_则是保存上一次运算的结果;

case3: 命名约定

通用标准:

case1: 命名的字符串中,不应该包含小写的L 大写的O(字符o的大写) 大写的I(字符i的大写),因为很多时候其与数字01非常难于区别;

case2: 命名字符串中,除了常量的变量名采用全大写字符串之外,一般不使用大写字符,一般全小写字符串,或一个字符串中个别字符大写;

1> 包名和模块名

全小写字符串,字符串内部可以采用下划线连接,也可以不采用下划线;对于c/c++编写的模块,模块的名称前加一个下划线用于与python编写的模块相区分;

2> 类名

首字符大写的小写字符串

3> 异常名

异常通常都是属于一个类,故此异常的命名规则遵循类的命名规则;需要注意的是,异常名要加一个'Error'的后缀,用于显示的说明该class是干啥的;

4> 变量名 函数名 函数的参数名 class的函数属性参数名

5> 类的函数属性和数据属性

case1: 共用属性采用上述函数名、变量名命名的规则进行命名;

case2: 对于私有属性,则在属性名前面加上单下划线或双下划线;

case3: 私有属性,若不希望被子类或外部直接调用到,则采用双下划线定义属性名,反之单下划线定义即可;

6> 常量命名

常量通常定义在全局,其采用全大写的字符的方式进行定义,全大写字符串可选择是否采用下划线;

2.15.代码块

定义:

程序由代码块构成,代码块作为一个程序的最小执行单位;

​ 一个程序文件中,一行顶级代码以及此行顶级代码包含的子级代码就构成了一个代码块;

案例:

​ a=100 //一个代码块

​ def test(): //整个函数构成一个代码块

​ pass

2.16.python的优化

case1:整数对象优化

​ python对整数对象,将一些频繁使用的整数对象缓存起来,在python的整个生命周期内,任何需要引用这些整数对象的地方,都不会直接创建新的对象而是直接引用,即将新的变量的变量值设定为python缓存的这个整数的内存地址; 这些频繁使用的整数为: [-5,256]

case2: 代码块优化

优化:同一个代码块中的不可变对象,只要值是相等的就不会重复创建新的对象。

案列:

​ >>> a=257

​ >>> def test():

​ ... b=257

​ ... c=257

​ ... print(a is b)

​ ... print(a is c )

​ ... print(b is c)

​ ...

​ >>> test()

​ False

​ False

​ True

​ >>>

2.17.编程规范

​ 代码应该用不损害其他Python实现的方式去编写(PyPy,Jython,IronPython,Cython,Psyco 等)。和像None这样的单例对象进行比较的时候应该始终用 is 或者 is not,永远不要用等号运算符。 if x 语句中,bool(x)为true是才会触发if代码块的执行;

​ 当使用富比较(rich comparisons,一种复杂的对象间比较的新机制,允许返回值不为-1,0,1)实现排序操作的时候,最好实现全部的六个操作符(eq, ne, lt, gt, ge)而不是依靠其他的代码去实现特定的比较。为了最大程度减少这一过程的开销, functools.total_ordering() 修饰符提供了用于生成缺少的比较方法的工具。

​ PEP 207 指出Python实现了反射机制。因此,解析器会将 y > x 转变为 x < y,将 y >= x 转变为 x <= y,也会转换x == y 和 x != y的参数。sort() 和 min()方法确保使用<操作符,max()使用>操作符。然而,最好还是实现全部六个操作符,以免在其他地方出现冲突。

始终使用def表达式,而不是通过赋值语句将lambda表达式绑定到一个变量上。

​ 推荐:

​ def f(x): return 2*x

​ 不推荐:

​ f = lambda x: 2*x

​ 第一个形式意味着生成的函数对象的名称是“f”而不是泛型“< lambda >”。这在回溯和字符串显示的时候更有用。赋值语句的使用消除了lambda表达式优于显式def表达式的唯一优势(即lambda表达式可以内嵌到更大的表达式中)。

posted @ 2019-12-24 14:58  大兵0815  阅读(210)  评论(0)    收藏  举报