Python编程规范和格式化工具

栏目: Python · 发布时间: 7年前

内容简介:摘要:PSF(Python Software Foundation),Python的官方组织。PSF 提供的文档包括:PEP 是 PSF 写出、收纳、提供给社区参考使用、包含新特性、规范性等内容的说明文档。

摘要:

PSF & PEP

PSF(Python Software Foundation),Python的官方组织。PSF 提供的文档包括:

PEP 是 PSF 写出、收纳、提供给社区参考使用、包含新特性、规范性等内容的说明文档。

PEP在 github 上撰写、管理,自动编译html、同步到 网站 上,从2000年开始创建,至今(2019.5)仍非常活跃,如果是python的developer,建议star或watch它,实时跟踪。

PEP分了8类: 核心类、已提交、已接收、讨论中、讨论完、归档、拒绝、废弃

  • 有些pep很庞大,如:pep8(python编程规范);也有些很简短,如:pep7(c编程规范)
  • 有些pep很一本正经,如:pep569(Python 3.8 Release Schedule);有些也很搞怪,如:pep20(Zen of Python,20条禅学)

要贡献 PEP,需要参考 pep12 的模板来写,并且 PEP 不是用 markdown 写的,而是 ReStructuredText,也是标记(markup)语言,语法比 markdown 稍复杂一点点,这里有一些语法说明:

普通 Python 开发人员必读的PEP有:

  • 编码规范
    • PEP8 :Python 编码规范
    • PEP7 :C 编码规范
  • 文档规范
    • PEP256 :文档系统工作机制
    • PEP257 :docstrings Conventions
    • PEP258 :注释与文档转换工具
    • PEP287 :reStructuredText 书写规则

PEP8 Style Guide for Python Code

核心类 pep 是 PEPs of PEPs,目前只有9个, PEP8 位列其中,内容是 Python 的编码规范,Python开发人员必读文档之一。

PEP8 从2001年创建,至今有141次提交:

Python编程规范和格式化工具

修改(提交)集中在2002、 2012~2016年,2019已相对稳定:

Python编程规范和格式化工具

参与撰写的人不少,但top3都是python官方的人:

Python编程规范和格式化工具

PEP8 极简版

PEP8 有网友翻译: python代码风格指南(PEP8中文版)

下面我来整理一份PEP8的极简版,相比上面的网友翻译,增补了:

  • Module级dunder
  • 尾随逗号

极简版正文:

写“可读的代码”

代码的使用频率上看:读取远大于编写,所以一定要写“可读的代码”

每级缩进4空格,不允许tab和空格混用

入参和if分开讨论

# 函数定义的入参比函数名多1级缩进
def long_function_name(
        var_one, var_two, var_three,
        var_four):
    print(var_one)

# 函数调用的入参可对准左括号 or 悬挂缩进1级
foo = long_function_name(var_one, var_two,
                         var_three, var_four)
foo = long_function_name(
    var_one, var_two,
    var_three, var_four)

# if条件语句跨行时缩进:加1级即可
if (this_is_one_thing
        and that_is_another_thing):
    do_something()

最大行宽79字符,文本块 72 字符,极限 99 字符

  • 以前通常在二元运算符(+-*/ and or…)之后续行
  • 现在推荐在二元运算符之前续行
    income = (gross_wages
            + taxable_interest
            + (dividends - qualified_dividends)
            - ira_deduction
            - student_loan_interest)

空行要尽量节约使用

  • 顶层函数和Class之间可以用2个空行
  • Class内的方法之间用1个空行

源文件字符编码尽量使用 utf-8

  • ASCII 和 utf-8 的源文件不需要“编码声明”
  • 标准库更严格:符号 必须 用ASCII,其他 尽量 英文字母
  • 注释or字符串可以用非ASCII字符 \x \u \U \N
: str1='\xE4'
: print(str1)
ä

: str2 = '\u4f60\u597d'
: print(str2)
你好

: str3='你好'.encode('unicode-escape')
: print(str3)
b'\\u4f60\\u597d'

import 每行导入1个模块

from xxx import *

Module级dunder必须在 __future__ 之后,其他import之前

  • dunder (double underscore, 双下划线)
  • 最早python对 __all__ 这种符号称为魔法变量、魔法函数,后来为了破除迷信,称为 double underscore method,但太长了,被简称为 dunder symbol、dunder method……
  • Module级的 dunder 有2个约束
    from __future__ import ...
    
from __future__ import barry_as_FLUFL

__all__ = ['a', 'b', 'c']
__version__ = '0.1'
__author__ = 'Cardinal Biggles'

import os
import sys

python 字符串的单引号与双引号等效

空格的讲究有很多

  • 括号(圆括号、方括号)内避免空格
    • 左括号之前避免空格
  • 逗号、冒号、分号之前避免空格,之后可有
    • 索引中的冒号前后都要避免空格
  • 赋值等操作符前后不能因为对齐而添加多个空格
  • 二元运算符两边放置一个空格
    • 优先级高的运算符或操作符的前后不建议有空格
    • 关键字参数和默认值参数的前后不要加空格
# 错误示范:
spam( ham[ 1 ], { eggs: 2 } ) # 括号里面太多空格
ham[1: 9], ham[1 :9], ham[1:9 :3] # 索引冒号前后不应有空格
long_variable = 3
x             = 1  # 不能为了对齐等号而加空格
i=i+1 # =和+左右都要有空格
submitted +=1 # += 右边没有空格
x = x * 2 - 1 # *优先级高,左右不应有空格
def complex(real, imag = 0.0): # 默认参数的=左右不能有空格
    return magic(r = real, i = imag)

function annotations = 前后有空格, :-> 前无后有

python3 中引入了 function annotations,它是一种注释性质的语法,用于声明入参的类型和默认值。

  • 2006年的 PEP3107 首先定义了 Function Annotations
  • 2014年的 PEP484 补充和修订了 Function Annotations
  • 2016年,又发展出了 PEP526 ,定义了 Variable Annotations
import enforce

@enforce.runtime_validation
def add_int(a: int, b: int = 0)-> int:
    return a + b

print(add_int.__annotations__)
  • 表明入参a是int型,b是int型且默认值0,返回值int型
  • func.__annotations__ 返回函数入参注释信息
  • 有@enforce则强制类型检查,不匹配报错;不加 @enforce 则只做告警,不报错
  • function annotations 的编程规范要求
    • =前后要有空格
    • 冒号和”->”的前无,后有。
      def add_int(a:int, b: int=0) -> int: # 错误示范,有3处错误
      def add_int(a: int, b: int = 0)-> int: # 正确示范

尾随逗号在Tuple中重要,List中无效;分行中有利,单行中冗余

尾随逗号(Trailing Commas)

FILES0 = ('setup.cfg')  # 0
FILES1 = ('setup.cfg',) # 1
FILES2 = 'setup.cfg',   # 2
FILES3 = ['setup.cfg', 'tox.ini']    # 3
FILES4 = ['setup.cfg', 'tox.ini', ]  # 4
FILES5 = [                           # 5
    'setup.cfg',
    'tox.ini',
    ]
  • 类型:0是str,1/2是tuple,3/4是list
: print(type(FILES0),type(FILES1),type(FILES2),type(FILES3),type(FILES4))                                                         
<class 'str'> <class 'tuple'> <class 'tuple'> <class 'list'> <class 'list'>
  • 1==2 —— Tuple中尾随逗号是重要的
In [42]: FILES1==FILES2
Out[42]: True
  • 3==4==5 —— List中尾随逗号是无效的
In [43]: FILES3==FILES4==FILES5
Out[43]: True
  • 5 中每行增加尾随逗号是有意义的,可以减少新增行时的工作量
  • 4 中单行增加尾随逗号是没有意义的。

注释书写规范参考 PEP257

  • 与代码自相矛盾的注释比没注释更差。修改代码时要优先更新注释!
  • 注释段落中的每个句子应该以句号+2个空格结束。
  • 文档化注释 (或称为:可生成文档的注释)需遵守 PEP257
    • 将来有空可以单讲一篇,先挖个坑吧

命名:可用一张表格说清

程序猿常见的命名风格多样:

Naming Styles 举例 使用场景 备注
单个小写字母 b 变量名 避免使用小写l(易与1,I混)
单个大写字母 B 变量名 避免使用大写O(易与0混)、I
小写串 lowercase 变量名,包名,模块名 模块名对应文件名,有线系统文件名不区分大小写
带下划线的小写 lower_case_with_underscores 函数名,类的公开方法
大写串 UPPERCASE 常量 通常在模块级别定义
带下划线的大写串 UPPER_CASE_WITH_UNDERSCORES 常量 同上
驼峰命名法
首字母大写的单词串
CapitalizedWords(CapWords) Class名 专有名次缩写可全大写,如HTTP
匈牙利命名法
混合大小写,首单词小写
mixedCase python抵制
极少特殊情况下用于函数名
带下划线,首字母大写 Capitalized_Words_With_Underscores python抵制,丑陋
短前缀分组+匈牙利或驼峰 bsp_getPower python抵制,与C划清界限
单前置下划线 _single_leading_underscore 用于不想被外部使用的全局变量
或局部变量
类的非公开方法和实例变量
弱内部使用
weak “internal use”
单后置下划线 single_trailing_underscore_ def func(class_='name') 用于避免与 Python关键词的冲突
双前置下划线 __double_leading_underscore 类Foo中的 __bar 会变成 _Foo__bar 当用于命名类属性,会触发名字重整
双前后下划线 __dunder_func__ Dunder(魔法)函数 不要自己发明这样的名字
__all__

编程建议

下面就不单纯是格式(format)的问题了,而是有利于程序运行的内容。

  • 要明白自己在用哪个python解释器
    • 官方整理出来好几十个
      • CPython: https://www.python.org/downloads/ 官网下载的既是
      • CPython衍生的 stacklessPython, wpython, microPython…
      • PyPy :Python in Python
      • Jython :Python in Java
      • IronPython :Python in C#
      • ActivePython
      • WinPython
    • CPython及其衍生底层是用C实现的,所以对C/Python API都有完美支持。非 C语言 实现的编译器虽然某些操作会快一些,但最大的问题是不支持某些只有C接口的库,如:numpy、scipy……
    • 不同的编译器之间效率有差别,官方建议你仔细研究、斟酌
  • if foo is not None 优于 if not foo is None
  • if foo == None 用法错误
  • 比较 排序 操作最好实现完整6个操作: __eq__, __ne__, __lt__, __le__, __gt__, __ge__
  • 变量赋值不要用lambda,而要用def,如: f = lambda x: 2*x #不推荐
  • 空”except:”子句(相当于except Exception)会捕捉SystemExit和KeyboardInterrupt异常,难以用Control-C中断程序,并可掩盖其他问题。只适用于2种情况
    • 打印出或记录了traceback,至少让用户将知道已发生错误
    • 代码需要做一些清理工作,并用 raise转发了异常,try…finally可以捕捉到它
  • 本地资源用with,使用with的资源要有独立的enter、exit方法
  • 函数或者方法在没有返回时要明确返回None
def foo(x):
    if x < 0:
        return  # No!请 return None
    return math.sqrt(x)
  • 使用字符串方法而不是string模块
    • Python不支持单字符类型,单字符在 Python 中也是作为一个字符串
# 字符串方法
>>> type(str)   # str是python关键字
<class 'type'>
>>> STR="Hello World"
>>> type(STR)
<class 'str'>
>>> str.lower(STR)
'hello world'
>>> STR.lower() # str.xxx() == STR.xxx()
'hello world'
>>> STR[::-1]   # 翻转字符串
'dlroW olleH'

>>> import string
>>> STR = "Hello {0}"
>>> f = string.Formatter()
>>> f.format(STR,"world") 
'Hello world'
>>> STR.format("World")
'Hello World
  • 字符串方法中检查前后缀:使用 .startswith()和.endswith()代替字符串切片
>>> STR[:5]=="Hello"        # 切片 —— No!
True
>>> STR.startswith("Hello") # Yes!
True
  • 使用isinstance()代替对象类型的比较
if isinstance(obj, int):    # Yes!
if type(obj) is type(1):    # No!
  • 判断序列(字符串、list、tuple)为空:
if not seq:     # Yes!
if len(seq):    # No!
  • 不要用 == 进行布尔比较
if greeting:            # Yes!
if greeting == True     # No!
if greeting is True:    # Worse

自动格式化工具

要实现 PEP8 中的大部分条目并不难,但要持之以恒、实现所有条目,应该还是挺难的。

一个人要实现 PEP8 中的条目并不难,但要保证一个团队都做到,应该还是挺难的。

如果有一个自动格式化工具,当我 Ctrl-S 保存文件的时候实时帮我按 PEP8 美化一下,上面2个问题就都不是问题了。

YAPF

Google 出品的 YAPF 可以满足你这方面的几乎所有需求。

$ pip install yapf
$ yapf [options] [files [files ...]]

常用的 options 有:

  • --diff : 输出diff文件,不修改源文件
  • --style STYLE :
    • “pep8” or “google”
    • 如果当前目录下有 .style.yapf 或 setup.cfg 文件,则从此文件中读取配置项
    • .style.yapf 文件示例
[yapf]
based_on_style = pep8
spaces_before_comment = 4
split_before_logical_operator = true

Black

Black 帮我们实现这个愿望。

Python编程规范和格式化工具

用了 Black,相当于放弃了自己的编码风格,完全由 Black 来接手,一个团队的代码就像一个人写的 —— 至少样子上是。

经过一段时间之后,个人手写水平也能提高,逐步逼近 PEP8 的要求。

$ pip install black
$ black [options] [mypythonfile 或 dir]
  • 常用的 options 有:
    • -t [py27|py33|py34|py35|py36|py37|py38]
      • Black 会自动逐个试探每个文件的python版本,应用不同的风格
    • --check :只检查,不修改源文件
    • --diff : 输出diff文件,不修改源文件
    • --include XXX , --exclude XXX : 操作目录时的筛选器

比较

Item YAPF Black 点评
License Apache2.0 MIT 两者都允许修改后闭源,即允许只发布二进制版本,但必须附带License。Apache要求每个文件头上都要附带,MIT只需要根目录下放一份即可。
Author Google Python 所以Black只支持PEP8,YAPF则可定制
创建日期 2015-03-18 2018-03-14 3月是个好季节
提交次数 1000+ 500+ 截至2019.5

找一段代码实战比较一下,从左至右依次是:原始文件、black处理后的文件、yapf依pep8处理过的文件

Python编程规范和格式化工具

  • 第1行:每次只import1个model —— 没有帮我改过来
  • 第2行:dunder 变量放置在 import 之前 —— 没有帮我改过来
  • 第9-18行:空格、空行,black和yapf都控制的不错
    • 第17行:google把索引中的冒号两边去掉了空格
  • 第19-23行:因为没有超过80列,续行都合并到1行了
  • 第24-25行:PEP8中推荐的写法,black、yapf都做了修正
  • 第28-32行:PEP8中推荐的写法,black微调,yapf大修 —— black稍优
  • 第34行:函数注释都能控制冒号左右的空格
  • 第37行:要用is而不是==来比较None —— 都没修改过来

可以看出 black 和 yapf 能做的和 PEP8 比较还是有限,且目前都还在 书写美化 上下功夫,在 代码优化 上不足。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Algorithms for Image Processing and Computer Vision

Algorithms for Image Processing and Computer Vision

Parker, J. R. / 2010-12 / 687.00元

A cookbook of algorithms for common image processing applications Thanks to advances in computer hardware and software, algorithms have been developed that support sophisticated image processing with......一起来看看 《Algorithms for Image Processing and Computer Vision》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

在线进制转换器
在线进制转换器

各进制数互转换器

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具