前言
Python 玩家在写Python 的时候一定要注意可读性,因为你可能需要二次修改,或者别人使用你的代码,可读性强都是至关重要的,因为Python 是没有Java c 之类的大括号的,一切全靠缩进,如果格式乱,可读性差,那真的是一坨不堪入目的乱码丫。
规范虽然重要,但是先后兼容依然也狠重要,所以在考虑向后兼容的时候,规范可以暂时放到一边,找到一个平衡点就好~。
一般看过我Python自动化办公教程的人都知道,Python万事全靠缩进,缩进是 4个空格,这个数字 “4“,将来你或者你的孩子在参加高考的时候,这个数字可能会出现在考卷上!
课程直达链接!点它,点它,点它:https://edu.51cto.com/sd/b12dd
社区PE8 规范
1、与分隔符对齐。
foo = long_function_name(var_one, var_two,
var_three, var_four)
2、添加4个空格以将参数与其余参数区分开。
def long_function_name(
var_one, var_two, var_three,
var_four):
print(var_one)
3、悬挂的缩进应添加一个级别。
foo = long_function_name(
var_one, var_two,
var_three, var_four)
4、多条件if 判断
# #没有额外的缩进。
if (this_is_one_thing and
that_is_another_thing):
do_something()
# 添加评论,这将在编辑器中提供一些区别
# 支持语法突出显示。
if (this_is_one_thing and
that_is_another_thing):
# 既然这两个条件都成立,那么我们可以断言。
do_something()
# 在条件延续行上添加一些额外的缩进。
if (this_is_one_thing
and that_is_another_thing):
do_something()
5、 多行构造的右花括号/括号/括号可以在列表最后一行的第一个非空白字符下对齐
my_list = [
1, 2, 3,
4, 5, 6,
]
result = some_function_that_takes_arguments(
'a', 'b', 'c',
'd', 'e', 'f',
)
6、空格是首选的缩进方法
7、 Python标准库是保守的,需要将行数限制为79个字符(文档字符串/注释数限制为72个)
8、包装长行的首选方法是在括号,方括号和花括号内使用Python的隐含行连续性。
通过将表达式包装在括号中,可以将长行分成多行。应优先使用这些,而不是使用反斜杠进行行连续。
有时反斜杠可能仍然合适。例如,带-语句的long多个不能使用隐式连续,因此可以使用反斜杠:
with open('/path/to/some/file/you/want/to/read') as file_1, \
open('/path/to/some/file/being/written', 'w') as file_2:
file_2.write(file_1.read())
9、运算符在换行之前
# Correct:
# easy to match operators with operands
income = (gross_wages
+ taxable_interest
+ (dividends - qualified_dividends)
- ira_deduction
- student_loan_interest)
发现pycharm 好玩的快捷键,ctrl+l 可以跳转到指定行指定字符处。
10、import
# Correct:
import os
import sys
# Correct:
from subprocess import Popen, PIPE
导入应按以下顺序分组:
-
标准库导入。
-
相关第三方进口。
-
本地应用程序/库特定的导入,您应该在每组导入之间放置一个空白行。
-
推荐绝对导入
import mypkg.sibling
from mypkg import sibling
from mypkg.sibling import example
- 相对导入
from . import sibling
from .sibling import example
11、 从包含类的模块中导入类时,通常可以这样拼写:
from myclass import MyClass
from foo.bar.yourclass import YourClass
#如果此拼写引起本地名称冲突,则应明确拼写它们:
import myclass
import foo.bar.yourclass
# 并使用" myclass.MyClass"和"foo.bar.yourclass.YourClass"
应该避免使用通配符导入(来自
通配符导入有一个合理的用例,它是将内部接口重新发布为公共API的一部分(例如,使用可选的加速器模块中的定义覆盖接口的纯Python实现,以及确切的定义将是事先未知)。
12、Python中的单引号和双引号效果是一样的,个人偏好单引号。
13、谨慎使用内联注释。
内联注释是与语句在同一行上的注释。内联注释应与该语句至少分隔两个空格
内联注释是不必要的,并且如果它们表明显而易见,则实际上会分散注意力。不要这样做:
14、文档型字符串
"""Return a foobang
Optional plotz says to frobnicate the bizbaz first.
"""
"""Return an ex-parrot."""
15、命名约定
1、首要原则:
对于用户而言,作为API公共部分可见的名称应遵循反映用法而不是实现的约定。
2、命名样式:
Python中使用的不同命名风格包括以下几种。
驼峰式命名法(CamelCase)。
混合式命名法(mixedCase)。
大写(UPPERCASE)或大写加下划线(UPPERCASEWITH_UNDERSCORES)。
前缀(leading)和后缀(trailing)下划线,有时是双下划线(doubled)。
小写元素和大写元素通常是一个单词,有时是几个单词连在一起。使用下划线的通常是缩写短语。使用一个单词要更好一些。前缀和后缀下划线用于标记私有元素和特殊元素。
这些风格被应用到以下几种情形。
变量。
函数和方法。
property。
类。
模块。
包。
CapWords中使用首字母缩写词时,请使用首字母缩写词的所有字母大写。因此,HTTPServerError比HttpServerError好。
3、 还有一种使用短的唯一前缀将相关名称组合在一起的样式
这在Python中使用不多,但是为了完整起见提到它
os.stat()函数返回一个元组,该元组的项目传统上具有诸如st_mode, st_size,st_mtime等名称
*4、_single_leading_underscore:“内部使用”指标较弱。**
例如,从M import *不会导入名称以下划线开头的对象。
5、避免使用的名称
避免使用字母 I ,O, l,.
6、软件包和模块
模块应使用简短的全小写名称, 如果模块名称可以提高可读性,则可以在模块名称中使用下划线。尽管不鼓励使用下划线,但Python软件包也应使用短小写全名
除了特殊模块init之外,模块名称都使用小写,不带下划线。
7、类名
类名通常应使用CapWords约定。
在接口被记录并主要用作可调用函数的情况下,可以代替使用函数的命名约定。
请注意,内置名称有一个单独的约定:大多数内置名称是单个单词(或两个单词一起运行),而CapWords约定仅用于异常名称和内置常量。
类名称始终采用驼峰式命名法,如果它们是模块的私有类,还可能有一个前缀下划线。
类和实例变量通常是名词短语,与用动词短语命名的方法名称构成使用逻辑:
8、类型变量名
在PEP 484中引入的类型变量的名称通常应使用CapWords,而应使用短名称:T,AnyStr,Num。建议将后缀_co或_contra添加到用于分别声明协变或反变行为的变量中:
from typing import TypeVar
VT_co = TypeVar('VT_co', covariant=True)
KT_contra = TypeVar('KT_contra', contravariant=True)
私有元素 两个前缀下划线,它会在运行时被解释器重命名,以避免与任何子类中的方法产生命名冲突。,
9、异常名称
因为异常应该是类,所以在这里适用类命名约定。但是,您应该在异常名称上使用后缀“ Error”(如果异常实际上是一个错误)。
10、全局变量名
(我们希望这些变量只能在一个模块内使用。)约定与函数的约定大致相同。
11、函数和变量名
函数名称应小写,必要时用下划线分隔单词以提高可读性。
变量名遵循与函数名相同的约定。
12、函数和方法参数
始终将self作为实例方法的第一个参数。
始终对类方法的第一个参数使用cls。
如果函数参数的名称与保留关键字发生冲突,通常最好在其后附加一个下划线,而不要使用缩写或拼写错误。因此,class_优于clss。(也许最好通过使用同义词来避免此类冲突。)
特殊方法
参数名称使用小写,如果需要的话可以加下划线。它们遵循与变量相同的命名规则。
13、方法名称和实例变量
使用函数命名规则:小写字母,必要时用下划线分隔单词,以提高可读性。
仅对非公共方法和实例变量使用一个前划线。
为避免名称与子类冲突,请使用两个前导下划线来调用Python的名称处理规则。
Python用类名来修饰这些名称:如果类Foo具有名为a的属性,则Foo . a不能访问它。(坚持的用户仍然可以通过调用Foo._Foo__a来获得访问权限。)通常,双引号下划线仅应用于避免名称与设计为子类的类中的属性发生冲突。
14、常数
常量通常在模块级别定义,并以所有大写字母书写,并用下划线分隔单词。示例包括 MAX_OVERFLOW和TOTAL。
16、编程建议
字符串连接: 用\'\'.join()形式。
与单例(如None)的比较应该始终使用 is或not进行,永远不要使用相等运算符进行
# Correct:
if foo is not None:
17、异常处理
# Correct:
try:
value = collection[key]
except KeyError:
return key_not_found(key)
else:
return handle_value(value)
18、用“has”或“is”前缀命名布尔元素
如果一个元素保存的是布尔值,is和has前缀提供一种自然的方式,使其在命名空间中的可读性更强,代码如下:
class DB:
is_connected = False
has_cache = False
19、用复数形式命名集合变量
如果一个元素保存的是集合变量,那么使用复数形式是一个好主意。有些映射在暴露为序列时也可以从中受益:
class DB:
connected_users = ['Tarek']
tables = {
'Customer': ['id', 'first_name', 'last_name']
}
20、用显式名称命名字典
如果一个变量保存的是映射,那么你应该尽可能使用显式名称。例如,如果一个字典保存的是个人地址,那么可以将其命名为persons_addresses,代码如下:
persons_addresses = {'Bill': '6565 Monty Road',
'Pamela': '45 Python street'}
persons_addresses['Pamela']
# '45 Python street'
21、避免通用名称
如果你的代码不是在构建一种新的抽象数据类型,那么使用类似list、dict、sequence或elements等专用名词是有害的,即使对于局部变量也一样。它使得代码难以阅读、理解和使用。还应该避免使用内置名称,以避免在当前命名空间中将其屏蔽(shadowing)。还应该避免使用通用的动词,除非它们在该命名空间中有意义。
相反,应该使用领域特定的术语,如下所示:
def compute(data): # 太过通用
for element in data:
yield element ** 2
def squares(numbers): # 更好一些
for number in numbers:
yield number ** 2
# 还有一系列前缀和后缀,虽然在编程中非常常见,但事实上应该避免出现在函数和类名称中:
manager;
object;
do、handle或perform。
这样做的原因是它们的含义模糊、模棱两可,且没有向实际名称中添加任何信息
22、避免现有名称
使用上下文中已经存在的名称是不好的做法,因为它会导致阅读代码时——特别是调试时——非常混乱,例如以下代码
23、参数的最佳实践
函数和方法的签名是代码完整性的保证,它们驱动函数和方法的使用并构建其API。
除了我们之前看到的命名规则之外,对参数也要特别小心。这可以通过3个简单的规则来实现。
通过迭代设计构建参数。
信任参数和测试。
小心使用魔法参数*args和**kwargs。
23.1 通过迭代设计构建参数
如果每个函数都有一个固定的、定义明确的参数列表,那么代码的鲁棒性会更好。但这在第一个版本中无法完成,所以参数必须通过迭代设计来构建。它们应该反映创建该元素所针对的使用场景,并相应地逐渐发展。
例如,如果添加了一些参数,它们应该尽可能有默认值,以避免任何退化:
class Service: # 版本1
def _query(self, query, type):
print('done')
def execute(self, query):
self._query(query, 'EXECUTE')
>>> Service().execute('my query')
done
import logging
class Service(object): # 版本2
def _query(self, query, type, logger):
logger('done')
def execute(self, query, logger=logging.info):
self._query(query, 'EXECUTE', logger)
>>> Service().execute('my query') # 旧式调用
>>> Service().execute('my query', logging.warning)
WARNING:root:done
23.2 小心使用*args和**kwargs魔法参数
*args和**kwargs参数可能会破坏函数或方法的鲁棒性。它们会使签名变得模糊,而且代码常常在不应该出现的地方构建小型的参数解析器,如下所示:
如果参数列表变得很长而且很复杂,那么添加魔法参数是很吸引人的。但这更表示它是一个脆弱的函数或方法,应该被分解或重构。
如果*args被用于处理元素序列(在函数中以相同方式处理),那么要求传入唯一的容器参数(例如iterator)会更好些,如下所示:
def fuzzy_thing(**kwargs):
if 'do_this' in kwargs:
print('ok i did')
if 'do_that' in kwargs:
print('that isdone')
print('errr... ok')
>>> fuzzy_thing(do_this=1)
ok i did
errr... ok
>>> fuzzy_thing(do_that=1)
that is done
errr... ok
>>> fuzzy_thing(hahaha=1)
errr... ok
如果参数列表变得很长而且很复杂,那么添加魔法参数是很吸引人的。但这更表示它是一个脆弱的函数或方法,应该被分解或重构。
如果*args被用于处理元素序列(在函数中以相同方式处理),那么要求传入唯一的容器参数(例如iterator)会更好些,如下所示
def sum(*args): # 可行
total = 0
for arg in args:
total += arg
return total
def sum(sequence): # 更好!
total = 0
for arg in sequence:
total += arg
return total
# *kwargs适用于同样的规则。最好固定命名参数,使方法签名更有意义,如下所示:
def make_sentence(**kwargs):
noun = kwargs.get('noun', 'Bill')
verb = kwargs.get('verb', 'is')
adj = kwargs.get('adjective', 'happy')
return '%s %s %s' % (noun, verb, adj)
def make_sentence(noun='Bill', verb='is', adjective='happy'):
return '%s %s %s' % (noun, verb, adjective)
另一种有趣的方法是创建一个容器类,将多个相关参数分组以提供执行上下文。这种结构与*args或**kwargs不同,因为它可以提供能够操作数值并且能够独立发展的内部构件(internals)。使用它作为参数的代码将不必处理其内部构件。
例如,传入函数的Web请求通常由一个类实例表示。这个类负责保存Web服务器传入的数据,代码如下:
def log_request(request): # 版本1
print(request.get('HTTP_REFERER', 'No referer'))
def log_request(request): # 版本2
print(request.get('HTTP_REFERER', 'No referer'))
print(request.get('HTTP_HOST', 'No host')
魔法参数有时是无法避免的,特别是在元编程中。例如,想要创建能够处理任何类型签名的函数的装饰器,它是不可或缺的。更普遍地说,在处理对函数进行遍历的未知数据时,魔法参数都很好用,代码如下:
import logging
def log(**context):
logging.info('Context is:\n%s\n' % str(context))