文档章节

Python 编码风格参考

Konghy
 Konghy
发布于 2017/05/24 23:13
字数 3007
阅读 41
收藏 0
点赞 0
评论 0

代码除了用来运行外,更多的是用来读。为了是代码的可读性更强,很多编程语言都有自己的编码规范。规范的制定是为了保持代码的一致性,以使代码更美观和易读。代码应该怎么样排版和编写并不是绝对的,所以一些地方会有争议。有时风格指南并不适用,最重要的知道何时不一致。当你无法判断该怎么做时,应该所参考下其他的例子。

本文仅是一个 Python 编码风格的参考,并不是一个规定,规定必须要这么去做。本文的目的应该是起一个指导作用,指导开发者去写更易读的代码。

一、代码编排

主要是缩进与空行的排版:

  • 1、使用 4 个空格进行缩进(编辑器都可以完成此功能),不推荐使用制表符,更不能混合使用制表符和空格。
  • 2、每行不超过 80 个字符,换行可以使用反斜杠,最好使用括号(Python 会将圆括号, 中括号和花括号中的行隐式的连接起来)。
  • 3、类和顶层函数定义之间空两行;类中的方法定义之间空一行;函数内逻辑无关段落之间空一行;其他地方尽量不要再空行。

二、文档编排

主要是整个源码文件的布局:

  • 1、模块内容的顺序:模块说明,模块文档字符串,导入语句,全局变量或者常量,其他定义。
  • 2、模块导入部分顺序:标准库,第三方模块,自定义模块;各部分之间空一行。
  • 3、不要在一个 import 语句中一次导入多个模块,比如 import os, sys 不推荐。
  • 4、导入模块时应该使用合适的方式来避免命名冲突,例如在适当的时候才使用 from xx import xx,尽量避免使用 from xx imoprt *
  • 5、在自已编写的模块中,如果需要使用 from xx import * 时,应该在导入语句后或者模块尾使用 __all__ 机制来限制导入规则。

三、语句编排

  • 1、通常每个语句应该独占一行。
  • 2、不要在行尾加分号, 也不要用分号将多条语句放在同一行。
  • 3、if/for/while 语句中,即使执行语句只有一句,也应尽量另起一行。
  • 4、不要在返回语句(return)或条件语句(if/for/while)中使用括号,除非是用于实现行连接。
  • 5、对于 if 语句, 在没有 else 且语句比较短时,可以在一行完成(但不推荐),比如:if foo: bar(foo).
  • 6、对于简单的类定义,也可以在一行完成(但不推荐),比如定义一个异常:class UnfoundError(Exception): pass.
  • 7、函数和方法的括号中使用垂直隐式缩进或使用悬挂缩进。
# 一行写不下时,有括号来连接多行,后续行应该使用悬挂缩进
if (this_is_one_thing
        and that_is_another_thing):
    do_something()

# 函数调用参数较多时,对准左括号
f = foo(a, b,
        c, d)

# 不对准左括号,但加多一层缩进,以和后面内容区别
def long_function_name(
        a, b, c,
        d, e):
    print(a, b, c, d, e)

# 列表、元组、字典以及函数调用时可以让右括号回退,这样更加美观
l = [
    1, 2, 3,
    4, 5, 6,
]

result = some_function(
    'a', 'b', 'c',
    'd', 'e', 'f',
)

四、空格使用

总体原则,避免不必要的空格。

  • 1、各种右括号前不要加空格。
  • 2、逗号、冒号、分号前不要加空格,但应该在它们后面加(除了在行尾)。
  • 3、函数的左括号前不要加空格。如 Func(1)。
  • 4、序列的左括号前不要加空格。如 list[2]。
  • 5、操作符左右各加一个空格,不要为了对齐增加空格。
  • 6、函数默认参数使用的赋值符左右省略空格。

良好的风格:

spam(ham[1], {eggs: 2})

if x == 4:
    print x, y; x, y = y, x

f = foo(1, 2, 3)

ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:]
ham[lower:upper], ham[lower:upper:], ham[lower::step]
ham[lower+offset : upper+offset]
ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
ham[lower + offset : upper + offset]

x = 1
y = 2
long_variable = 3

def foo(a, b, c=0):
    return moo(m=a, n=b, o=c)

不好的风格:

spam( ham[ 1 ], { eggs: 2 } )

if x == 4 :
    print x , y ; x , y = y , x

f = foo (1, 2, 3)

ham[lower + offset:upper + offset]
ham[1: 9], ham[1 :9], ham[1:9 :3]
ham[lower : : upper]
ham[ : upper]

x             = 1
y             = 2
long_variable = 3

def foo(a, b, c = 0):
    return moo(m = a, n = b, o = c)

五、注释

总体原则,错误的注释不如没有注释。所以当一段代码发生变化时,第一件事就是要修改注释。注释尽量使用英文,最好是完整的句子,首字母大写,句后要有结束符,结束符后跟两个空格,开始下一句。如果是短语,可以省略结束符。注释应该在 # 后加一个空格才开始写注释内容。

  • 1、块注释,在一段代码前增加的注释。段落之间用只有 ‘#’ 的行间隔。比如:
# Description : Module config.
#
# Input : None
#
# Output : None
  • 2、行注释,在一句代码后加注释。应该尽量在语句后空两格后再开始注释。当有连续的行注释时,为了美观可以让 ‘#’ 对齐。 在语句比较长时,应该尽量少使用行注释。比如:
person = {
    "name": "huoty",  # 姓名
    "age": 26,        # 年龄
    "stature": 169,   # 身高
    "weight": 60,     # 体重
}

print person  # 输出信息
  • 3、对类或者函数的说明,尽量不要在其定义的前一行或者后一行用块注释的形式来说明,而应该使用文档字符串(docstring)

  • 4、使用 TODO 注释来标记待完成的工作,团队协作中,必要的时候应该写上你的名字或者联系方式,比如:

# TODO(sudohuoty@gmail.com): Use a "*" here for string repetition.
# TODO(Huoty) Change this to use relations.
# 你可能会认为你读得懂以下的代码。但是你不会懂的,相信我吧。  

# 要是你尝试玩弄这段代码的话,你将会在无尽的通宵中不断地咒骂自己为什么会认为自己聪明到可以优化这段代码。  
# so,现在请关闭这个文件去玩点别的吧。  

# 程序员1(于2010年6月7日):在这个坑临时加入一些调料  
# 程序员2(于2011年5月22日):临你个屁啊  
# 程序员3(于2012年7月23日):楼上都是狗屎,鉴定完毕  
# 程序员4(于2013年8月2日):fuck 楼上,三年了,这坑还在!!!  
# 程序员5(于2014年8月21日):哈哈哈,这坑居然坑了这么多人,幸好我也不用填了,系统终止运行了,you're died  

六、文档描述

  • 1、尽量为所有的共有模块、函数、类、方法写 docstring

  • 2、前三引号后不应该换行,应该紧接着在后面概括性的说明模块、函数、类、方法的作用,然后再空一行进行详细的说明。后三引号应该单独占一行。比如:

"""Convert an API path to a filesystem path

If given, root will be prepended to the path.
root must be a filesystem path already.
"""
  • 3、如果要在 docstring 中对函数或者方法的参数以及返回值进行说明,可以参考如下形式:
"""Start a kernel for a session and return its kernel_id.                                                                                             

Parameters
----------
kernel_id : uuid
    The uuid to associate the new kernel with. If this
    is not None, this kernel will be persistent whenever it is
    requested.
path : API path
    The API path (unicode, '/' delimited) for the cwd.
    Will be transformed to an OS path relative to root_dir.
kernel_name : str
    The name identifying which kernel spec to launch. This is ignored if
    an existing kernel is returned, but it may be checked in the future.

Return a kernel id
"""

七、命名规范

  • 1、模块命名尽量短小,使用全部小写的方式,可以使用下划线。
  • 2、包命名尽量短小,使用全部小写的方式,不可以使用下划线。
  • 3、类的命名使用驼峰命令的方式,即单词首字符大写,类名应该全部使用名词。
  • 4、异常命令应该使用加 Error 后缀的方式,比如:HTTPError。
  • 5、全局变量尽量只在模块内有效,并且应该尽量避免使用全局变量。
  • 6、函数命名使用全部小写的方式,使用下划线分割单词,并采用动宾结构。
  • 7、常量命名使用全部大写的方式,使用下划线分割单词。
  • 8、类的属性(方法和变量)命名使用全部小写的方式,使用下划线分割单词。
  • 9、变量、类属性等命令尽量不要使用缩写形式,除了计数器和迭代器,尽量不要使用单字符名称。
  • 10、类的方法第一个参数必须是 self,而静态方法第一个参数必须是 cls。
  • 11、在模块中要表示私有变量或者函数时,可以在变量或者函数前加一个下划线 _foo, _show_msg
  • 12、在 Python 中没有诸如 public、private、protected 等修饰符,而在类的定义中往往会有类似这样的需求,那么可以在属性或者方法前加一个下划线表示 protected,加两个下划线来表示 private。加两个下划线的变量或者方法没法直接访问。比如:类 Foo 中声明 __a, 则不能用 Foo.__a 的方式访问,但可以用 Foo._Foo__a 的方式访问。`

八、程序入口

Python 属于脚本语言,代码的运行是通过解释器对代码文件进行逐行解释执行来完成的。它不像其他编程语言那样有统一的入口程序,比如 Java 有 Main 方法,C/C++ 有 main 方法。Python 的代码文件除了可以被直接执行外,还可以作为模块被其他文件导入。所有的顶级代码在模块导入时都会被执行,当希望模块被导入时,应该避免主程序被执行。这样就需要把主程序放到 if __name__ == '__main__' 代码块中,比如:

def main():
      ...

if __name__ == '__main__':
    main()

一个包除了能够被导入外,也可以通过 python -m package 的方式被直接执行,前提是包中需要有 __main__.py,这个文件可以说是包的程序入口,包中有了这个文件就可以用 Python 的 -m 参数来直接运行。

九、编码建议

  • 1、尽可能使用 'is' 和 'is not' 取代 '==',比如 if x is not None 要优于 if x。

  • 2、用 "is not" 代替 "not ... is",前者的可读性更好。

  • 3、使用基于类的异常,每个模块或包都有自己的异常类,此异常类继承自 Exception。

  • 4、异常中尽量不要使用裸露的 except,except 后应该跟具体的 exceptions。

  • 5、使用 startswith() 和 endswith() 代替切片进行序列前缀或后缀的检查。

  • 6、使用 isinstance() 比较对象的类型,而不是 type(),比如:

# Yes:  
if isinstance(obj, int)

# No:  
if type(obj) is type(1)
  • 7、判断序列是否为空时,不用使用 len() 函数,序列为空时其 bool 值为 False,比如:
# Yes:  
if not seq
if seq

# No:  
if len(seq)
if not len(seq)
  • 8、字符串后面不要有大量拖尾空格。

  • 9、使用 join 合并的字符串,字符串方法 join 可以合并 list、tuple、iterator 中的元素,效率比连接符 + 高。

  • 10、使用 while 1while True 更快。

  • 11、使用 **pow 快 10 倍以上。

  • 12、使用迭代器和生成器代替列表等数据结构效率更高,使用列表(字典)解析式和生成器表达式比用循环效率更高。

参考资料

© 著作权归作者所有

共有 人打赏支持
Konghy
粉丝 7
博文 22
码字总数 31889
作品 0
朝阳
程序员
python基础autopep8__python代码规范

关于PEP 8 PEP 8,Style Guide for Python Code,是Python官方推出编码约定,主要是为了保证 Python 编码的风格一致,提高代码的可读性。 官网地址:https://www.python.org/dev/peps/pep-0...

_周小董
05/01
0
0
【原创】Python 源文件编码解读

以下内容源于对 PEP-0263 的翻译和解读,同时给出了一些网上网友的说法。 ======== 我是分割线 ======== 原文地址:PEP 0263 -- Defining Python Source Code Encodings 【摘要】 给出声明 ...

摩云飞
2013/09/26
0
1
个人总结——全面的『Python编码规范』

本文目的 『动态类型一时爽,代码重构火葬场』,说的是:动态语言在初期开发比较爽,但是到后期维护起来比较困难。Python 作为动态语言之一,自然也会有这样的缺点。其实说『火葬场』,也没有...

hezhiming
05/18
0
0
Python学习路线(针对具备一定编程经验者)

相比C,C++,JAVA等编程语言,Python是易学的。但要想深入地理解Python,并熟练地编写Python风格的Python代码。我想还是有一长段路程要走的。下面即是我的一点经验总结,主要是为了整理自己学习...

Thebreezecomes
06/28
0
0
Python 与 Javascript 之比较

最近由于工作的需要开始开发一些Python的东西,由于之前一直在使用Javascript,所以会不自觉的使用一些Javascript的概念,语法什么的,经常掉到坑里。我觉得对于从Javascript转到Python,有必...

naughty
2014/05/13
0
39
关于python指定字符编码的说明

要让python文件支持UTF-8输入和显示,我们熟悉在文件第二行加入如下注释: # -- coding: -- 但是为什么要这么写,到底写成什么格式是合法的,可以看下面这段说明: Defining the Encoding Py...

huang19830104
06/28
0
0
Python的编码注释# -*- coding:utf-8 -*-

如果要在python2的py文件里面写中文,则必须要添加一行声明文件编码的注释,否则python2会默认使用ASCII编码。 -- coding:utf-8 -- 问题就来了,为什么要如此声明? 首先请参考python的 PEP ...

Lucups
2014/03/07
0
0
[ZZ]Python的编码注释# -*- coding:utf-8 -*-

如果要在python2的py文件里面写中文,则必须要添加一行声明文件编码的注释,否则python2会默认使用ASCII编码。 # -- coding:utf-8 -- 问题就来了,为什么要如此声明? 首先请参考python的PEP...

学徒1986
2013/07/24
0
0
大神整理的python资源大全

Python基本安装: http://www.python.org/ 官方标准Python开发包和支持环境,同时也是Python的官方网站; http://www.activestate.com/ 集成多个有用插件的强大非官方版本,特别是针对Windo...

openthings
2015/12/15
0
0
字符串转换ASCII码、Unicode码

将字符串转成16进制的ASCii码的值 python: 使用python 内置函数repr可以将非ascii码转换成x**的样式,如下: >>> a='我们都是中国人'>>> print repr(a)'xe6x88x91xe4xbbxacxe9x83xbdxe6x98x......

yoyoso
2014/12/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

单身税的时代就要来临,你还没有用Python帮你找一个女朋友吗?

单身税的历史可以追溯到2015年韩国的新政, 低生育率逼得韩国产生了这一政策。 现在我国也要实行这一政策, 很多单身狗就接受不了了 很可惜,国家不包分配对象, 男的都说找对象难, 有没有向...

猫咪编程
4分钟前
0
0
Java中 发出请求获取别人的数据(阿里云 查询IP归属地)

1.效果 调用阿里云的接口 去定位IP地址 2. 代码 /** * 1. Java中远程调用方法 * http://localhost:8080/mavenssm20180519/invokingUrl.action * @Title: invokingUrl * @Description: * @ret......

Lucky_Me
8分钟前
0
0
protobuf学习笔记

相关文档 Protocol buffers(protobuf)入门简介及性能分析 Protobuf学习 - 入门

OSC_fly
昨天
0
0
Mybaties入门介绍

Mybaties和Hibernate是我们在Java开发中应用的比较多的两个ORM框架。当然,目前Mybaties正在慢慢取代Hibernate,这是因为相比较Hibernate而言Mybaties性能更好,响应更快,更加灵活。我们在开...

王子城
昨天
0
0
编程学习笔记之python深入之装饰器案例及说明文档[图]

编程学习笔记之python深入之装饰器案例及说明文档[图] 装饰器即在不对一个函数体进行任何修改,以及不改变整体的原本意思的情况下,增加函数功能的新函数,因为这个新函数对旧函数进行了装饰...

原创小博客
昨天
0
0
流利阅读笔记33-20180722待学习

黑暗中的生物:利用奇技淫巧快活生存 Daniel 2018-07-22 1.今日导读 如果让你在伸手不见五指的黑暗当中生存,你能熬过几天呢?而大千世界,无奇不有。在很多你不知道的角落,有些生物在完全黑...

aibinxiao
昨天
2
0
Hystrix降级逻辑中如何获取触发的异常

通过之前Spring Cloud系列教程中的《Spring Cloud构建微服务架构:服务容错保护(Hystrix服务降级)》一文,我们已经知道如何通过Hystrix来保护自己的服务不被外部依赖方拖垮的情况。但是实际...

程序猿DD
昨天
0
0
gin endless 热重启

r := gin.New()r.GET("/", func(c *gin.Context) {c.String(200, config.Config.Server.AppId)})s := endless.NewServer(":8080", r)s.BeforeBegin = func(add string) ......

李琼涛
昨天
0
0
JAVA模式之代理模式

平时一直在用spring,spring中最大的特效IOC和AOP,其中AOP使用的就是代理模式.闲着无聊,随手写了一个代理模式,也记录下代理模式的实现Demo. 比如现在有一个场景是:客户想要增加一个新的功能,...

勤奋的蚂蚁
昨天
0
0
ES15-JAVA API 索引管理

1.创建连接 创建连接demo package com.sean.esapi.client;import java.net.InetSocketAddress;import org.elasticsearch.action.get.GetResponse;import org.elasticsearch.clien......

贾峰uk
昨天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部