多年来,我写的Python越多,我就越发现自己同意大多数指导方针,尽管我一直并故意为了自己的原因打破了一些。
我很想知道PEP 8(或其他PEP也可能)人们虔诚地坚持和为什么,以及人们发现不方便或不足的内容。
在我的情况下(以及一般的工作),我们只有少数几个偏离的东西:
所以,那些是我的,以及我“违反”PEP背后的原因(有些是共享的,有些是同事不赞同的)。我很想知道其他Pythonistas在这方面做了什么和不做什么。
“每行79个字符”部分是无稽之谈。他们自己的例子显示了执行此操作时代码的不可读性:
class Rectangle(Blob):
def __init__(self, width, height,
color='black', emphasis=None, highlight=0):
if width == 0 and height == 0 and \
color == 'red' and emphasis == 'strong' or \
highlight > 100:
raise ValueError("sorry, you lose")
if width == 0 and height == 0 and (color == 'red' or
emphasis is None):
raise ValueError("I don't think so -- values are %s, %s" %
(width, height))
Blob.__init__(self, width, height,
color, emphasis, highlight)
这就像尝试 - 阅读 新闻艺术 写的 像这样。
十多年来,80列终端并不是一个严肃的开发环境。当我确实需要在瘫痪的80x25环境中进行编辑时,编辑器包装是一个小小的不便;为了避免这种情况,我不会在正常开发期间破坏我的代码。
120列包装对于现代开发是完全合理的,我对140没有任何问题。该指南已经过时,并且会导致难以读取的难以阅读的代码。
我的“承认违规”是关于“如果”
PEP8在一行中没有说多个语句,所以如果我们必须这样做:
if cond:
actions
...
但是当只有一个动作时,我更喜欢一行,例如我更喜欢 :
if a == 0: b = 0
比:
if a == 0:
b = 0
PEP 8的“问题”在于它倾向于个人偏好的领域,这些领域对于大多数程序员来说具有相当大的情感。
就我个人而言,camelCase vs下划线和列对齐指令是常量问题。我在这里也看到了很多其他的反应,有时候我会故意破坏PEP 8,因为在那种特殊情况下它只是“有意义”。
我的Python编程生涯中有一点我只是放弃并转向(使用)PEP 8.对于大多数项目来说相对容易,所以现在我唯一的主要问题是列对齐。那个人太乱了,不服从(尽管我还是讨厌地做)。无论如何,由于我的“放弃”,我的代码现在对我的同事更具可读性 - 而且 - 令人惊讶的是:甚至对我来说(除了列对齐的东西:p)。
我还必须认识到PEP 8为python本身做了什么:在2.x(非兼容)和3.x(兼容)之间,我发现更容易“总是知道”特定函数的名称是什么。 Python的“电池”现在排序得更好。
我使用pylint,http://pypi.python.org/pypi/pylint,它是一个很好的工具,可以让您和其他开发人员访问您的代码,保持您的代码清洁和可读。
但是,我没有涵盖您所说的所有主题,但它非常有用。
你可以有这样的报告:
carlos@debian:~/src/fcl/cltools$ pylint numbertoletters.py
No config file found, using default configuration
************* Module numbertoletters
C: 1: Missing docstring
C: 56:es_numero: Missing docstring
C: 56:es_numero: Invalid name "s" (should match [a-z_][a-z0-9_]{2,30}$)
C: 56:es_numero: Invalid name "s" (should match [a-z_][a-z0-9_]{2,30}$)
C: 69:convertnumbertoletters: Empty docstring
C: 90:convertnumbertoletters: Operator not preceded by a space
numero='%(numero)09d' % {'numero' : int(parte_entera)}
^
C: 92:convertnumbertoletters: Comma not followed by a space
for i in [0,3,6]:
^^
W: 69:convertnumbertoletters: Unused argument 'languaje'
C:108:unidades: Empty docstring
C:108:unidades: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:108:unidades: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:112:unidades: Invalid name "u" (should match [a-z_][a-z0-9_]{2,30}$)
C:118:teens: Empty docstring
C:118:teens: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:118:teens: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:122:teens: Invalid name "t" (should match [a-z_][a-z0-9_]{2,30}$)
C:127:tens: Empty docstring
C:127:tens: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:127:tens: Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
C:131:tens: Invalid name "t" (should match [a-z_][a-z0-9_]{2,30}$)
C:137:tercia: Empty docstring
C:141:tercia: Operator not preceded by a space
numero='%(numero)03d' % {'numero' : int(num)}
^
C:143:tercia: Invalid name "a" (should match [a-z_][a-z0-9_]{2,30}$)
C:144:tercia: Invalid name "b" (should match [a-z_][a-z0-9_]{2,30}$)
C:145:tercia: Invalid name "c" (should match [a-z_][a-z0-9_]{2,30}$)
C:163:tercia: Operator not followed by a space
resultado ='veinti '+unidades(c)
^
C:165:tercia: Operator not followed by a space
elif b >=3 and b <= 9:
^^
C:178:tercia: Operator not followed by a space
resultado ='ciento '+unidades(c)
^
C:192:tercia: Operator not followed by a space
resultado ='ciento veinti '+unidades(c)
^
C:204:tercia: Operator not preceded by a space
prefix='quinientos '
^
C:206:tercia: Operator not preceded by a space
prefix='setecientos '
^
C:208:tercia: Operator not preceded by a space
prefix='novecientos '
^
C:210:tercia: Operator not preceded by a space
prefix=unidades(a)+'cientos '
^
R:137:tercia: Too many return statements (23/6)
R:137:tercia: Too many branches (41/12)
R:137:tercia: Too many statements (73/50)
Report
======
141 statements analysed.
Raw metrics
-----------
+----------+-------+------+---------+-----------+
|type |number |% |previous |difference |
+==========+=======+======+=========+===========+
|code |144 |68.25 |NC |NC |
+----------+-------+------+---------+-----------+
|docstring |5 |2.37 |NC |NC |
+----------+-------+------+---------+-----------+
|comment |57 |27.01 |NC |NC |
+----------+-------+------+---------+-----------+
|empty |5 |2.37 |NC |NC |
+----------+-------+------+---------+-----------+
Statistics by type
------------------
+---------+-------+-----------+-----------+------------+---------+
|type |number |old number |difference |%documented |%badname |
+=========+=======+===========+===========+============+=========+
|module |1 |NC |NC |0.00 |0.00 |
+---------+-------+-----------+-----------+------------+---------+
|class |0 |NC |NC |0 |0 |
+---------+-------+-----------+-----------+------------+---------+
|method |0 |NC |NC |0 |0 |
+---------+-------+-----------+-----------+------------+---------+
|function |6 |NC |NC |0.00 |0.00 |
+---------+-------+-----------+-----------+------------+---------+
Duplication
-----------
+-------------------------+------+---------+-----------+
| |now |previous |difference |
+=========================+======+=========+===========+
|nb duplicated lines |0 |NC |NC |
+-------------------------+------+---------+-----------+
|percent duplicated lines |0.000 |NC |NC |
+-------------------------+------+---------+-----------+
Messages by category
--------------------
+-----------+-------+---------+-----------+
|type |number |previous |difference |
+===========+=======+=========+===========+
|convention |32 |NC |NC |
+-----------+-------+---------+-----------+
|refactor |3 |NC |NC |
+-----------+-------+---------+-----------+
|warning |1 |NC |NC |
+-----------+-------+---------+-----------+
|error |0 |NC |NC |
+-----------+-------+---------+-----------+
Messages
--------
+-----------+------------+
|message id |occurrences |
+===========+============+
|C0103 |14 |
+-----------+------------+
|C0322 |6 |
+-----------+------------+
|C0112 |5 |
+-----------+------------+
|C0323 |4 |
+-----------+------------+
|C0111 |2 |
+-----------+------------+
|W0613 |1 |
+-----------+------------+
|R0915 |1 |
+-----------+------------+
|R0912 |1 |
+-----------+------------+
|R0911 |1 |
+-----------+------------+
|C0324 |1 |
+-----------+------------+
Global evaluation
-----------------
Your code has been rated at 7.45/10
I hope it helps.
我强烈建议使用pylint对代码进行评级,并保持标准的编程方式,特别是在开发人员社区中。 =)
我希望它有所帮助。
python-mode.el,https://launchpad.net/python-mode
同时允许定制风格:
M-x自定义变量RET py-docstring-style RET
默认值为pep-257-nn
实施的款式有DJANGO,ONETWO,PEP-257,PEP-257-NN,SYMMETRIC和NIL。
NIL的值不关心引号位置,并且会将docstrings视为普通字符串,任何其他值都可能导致以下docstring样式之一:
DJANGO:
"""
Process foo, return bar.
"""
"""
Process foo, return bar.
If processing fails throw ProcessingError.
"""
ONETWO:
"""Process foo, return bar."""
"""
Process foo, return bar.
If processing fails throw ProcessingError.
"""
PEP-257:
"""Process foo, return bar."""
"""Process foo, return bar.
If processing fails throw ProcessingError.
"""
PEP-257-NO:
"""Process foo, return bar."""
"""Process foo, return bar.
If processing fails throw ProcessingError.
"""
对称:
"""Process foo, return bar."""
"""
Process foo, return bar.
If processing fails throw ProcessingError.
"""
当我写小脚本时,我经常只使用两个空格。
我总是对docstrings使用相同的模式:
def function():
"""
Even if it's a single line.
"""
PEP8表示要避免“在赋值(或其他)操作符周围有多个空格将它与另一个操作符对齐”并且“从不使用多个空格”围绕数学运算符,但我不遵循这一点。
当相邻行相关或非常相似时,我经常添加“无关的空白”,但不完全相同:
search_start = (f - f_1/3) * n/fs
search_stop = (f + f_1/3) * n/fs
b_lpf, a_lpf = filter(N, 2*pi*fc, 'low', analog=True)
b_hpf, a_hpf = filter(N, 2*pi*fc, 'high', analog=True)
p[x > 1] = np.cosh(order * np.arccosh( x[x > 1]))
p[x < -1] = (1 - 2 * (order % 2)) * np.cosh(order * np.arccosh(-x[x < -1]))
b0 = (1 + cos(w0))/2
b1 = -(1 + cos(w0))
同样,令人讨厌的是,我以可读的方式格式化code style warnings for arrays of numbers,它们通常由库本身格式化:
a = array([[-0.198, 0.248, -1.17 , -0.629, 1.378],
[-1.315, 0.947, -0.736, -1.388, 0.389],
[ 0.241, -0.98 , 0.535, 0.951, 1.143],
[-0.601, 1.286, -0.947, 0.037, -0.864],
[ 0.178, -0.289, -1.037, -1.453, -0.369]])
PEP8宁愿让它像这样格式化,显然,因为我们不能在逗号之前或括号之后有额外的空格,即使它提高了可读性:
a = array([[-0.198, 0.248, -1.17, -0.629, 1.378],
[-1.315, 0.947, -0.736, -1.388, 0.389],
[0.241, -0.98, 0.535, 0.951, 1.143],
[-0.601, 1.286, -0.947, 0.037, -0.864],
[0.178, -0.289, -1.037, -1.453, -0.369]])
PEP8说
请注意,最重要的是,结束多行文档字符串的“”“应该在一行上,并且最好在前面加一个空行,例如:
"""Return a foobang Optional plotz says to frobnicate the bizbaz first. """
我觉得这很奇怪,因为它只是“无关的空白”,并且没有明显的原因,对开场报价的处理与报价不同。
理由是在PEP 257:
BDFL建议在多行文档字符串中的最后一个段落与其结束引号之间插入一个空行,将结束引号放在一行上。这样,可以在其上使用Emacs的fill-paragraph命令。
Emacs,真的吗?每个人都应该做一些奇怪的事情来迎合特定编辑工具中特定命令的特性?
我还认为将文档字符串的开头放在与引号相同的行(不是必需的,但建议的)上是很奇怪的,同时坚持将结束引用放在他们自己的行上。我认为这更符合逻辑,应该用于单行和多行文档字符串:
def foobang(bizbaz, plotz=None):
"""
Return a foobang
Optional plotz says to frobnicate the bizbaz first.
"""
if plotz is not None:
...
更新:粗体部分已被删除,现在它只是说“将结束引号单独放在一行”,并且“汇总行可能与开头报价在同一行或在下一行”。
我不同意这点:
- Imports should usually be on separate lines, e.g.:
Yes: import os
import sys
No: import sys, os
我总是一起写简单的进口。我认为将它们全部写在不同的行上并没有任何好处:它所做的就是在每个源文件的顶部添加膨胀,并将一些简洁的东西变成简单易用的东西,例如边界样板。一些非常冗长的东西,它开始很容易从其他文件中复制和粘贴。
这是立即可读和可理解的:
import sys, os, time, gc, inspect, math, doctest
它简短,易于浏览,易于添加。如果在一行上有太多,当然,或者如果我需要import
导入,我会使用多个from
语句。
我通常也会将标准库导入与我自己的模块和其他库的导入分开,这与PEP8推荐的分组概念一致。
标准至关重要,PEP 8是我坚持的非常好的风格指南。我不同意的唯一指导是数学运算符周围的间距。 例如,PEP8坚持以下间距
Without PEP8 With PEP8
----------------------------------------------------------------
y = sqrt(x**2 + y**2) y = sqrt(x ** 2 + y ** 2)
a*x**3 + b*x**2 + c*x + d a * x ** 3 + b * x ** 2 + c * x + d
10**(a*x + b) 10 ** (a * x + b)
F = V/(sqrt(g*h) + epsilon) F = V / (sqrt(g * h) + epsilon)
a*cos(nx/pi) + b*sin(nx/pi) a * cos(nx / pi) + b * sin(nx / pi)
我想要顺从,但这是我正在努力的一个领域。还有其他人也觉得PEP8间距让数学难以阅读吗?
更新:
PEP8是corrected推荐左边的格式,同时劝阻右边的格式:
是:
i = i + 1 submitted += 1 x = x*2 - 1 hypot2 = x*x + y*y c = (a+b) * (a-b)
没有:
i=i+1 submitted +=1 x = x * 2 - 1 hypot2 = x * x + y * y c = (a + b) * (a - b)
我公司的风格指南专门要求标签,而不是空格。 PEP 8暗示空间是可取的,但我们发现了相反的情况。我喜欢在VIM中看到代码缩进4个“空格”,同事喜欢Emacs中的8个“空格”。使用选项卡可以让我们设置编辑器以显示我们喜欢的代码。
请注意,在其他基于C语言中,缩进实际上只是格式化,但在Python缩进中是语法,因此我们认为indentation level 2
应该用2
表示某些东西(即制表符)而不是4
或某些东西的8
(即空格)。
缩进字符选择可能是原始的圣火焰战争(甚至在VIM / Emacs火焰战争之前),所以我确实希望被修改为遗忘以表达对该主题的意见!
多线条件等:PEP-8明确表示要在二元运算符之后而不是在它之前中断。我担心我无法看到它的吸引力。对于我来说,在条件之前打破更有意义,因此在包裹/续行中,每个子行以条件开头:
if (condition1 \
or condition2 \
or condition3):
do_something()
可以看出,我还想为子线添加一个额外的缩进,以便它们在视觉上偏离下面的块。 PEP-8没有明确说明这一点(是吗?),但是这些例子的子行与开头的括号排成一行。
我总是使用4个空格,我尝试每行最多使用79个字符,有时候不可能。我过去也使用过像“import sys,os”这样的导入。总的来说,我试着坚持PEP 8。
编辑:也使用:
def foobar():
"""
foobar
"""
用于文档
PEP 8说:
是:
x = 1
y = 2
long_variable = 3
没有:
x = 1
y = 2
long_variable = 3
我通常会遵循它,但为了更好的可读性,我有时会使用另一种变体:
x = 1
y = 2
long_variable = 3