多年来,我写的Python越多,我发现自己越多地同意大多数指南,尽管我一直并故意为了自己的原因打破了一些。
我很想知道PEP 8(或其他PEP可能)人们虔诚地坚持和为什么,以及人们发现不方便或不足的内容。
在我的情况下(以及一般的工作),我们只有少数几个偏离的地方:
下划线小写名称,我可以看到它的重点,因为它将始终保持一致,但我们倾向于使用lowerCamelCase,即使偶尔会引入一些不一致(例如部分或错误大写的首字母缩略词)以及通常只追求刺激的话语。主要是因为我们经常使用的几乎所有的API都使用camelCase(一些较高,一些较低),并且因为某些原因我发现它更容易阅读,并且倾向于将下划线保留为分离令牌或规定的修改/模糊。
我仍然无法让自己按照PEP规定的内容来解决问题。 new和init我倾向于在类下面没有空行,因为我总是希望用类名和args读取它们,这些方法有助于类中相同的功能范围(比如init,get和set)同一个attrib或一组attribs)我只分开单个空格,我喜欢类之间的三个空格,两个方法之间我不会在该对象的地图中进行心理聚合。 这再次纯粹是为了代码的视觉冲击和可读性。我发现流量控制中的内容非常紧凑,方法和物体之间的这种间距一直引起我的注意,我希望它在代码停放几个月后重新读取。它对我选择的编辑中的折叠反应也很好。
有些事情反而是我坚持,当我阅读其他文字时,这让我疯狂,是标签而不是空格(特别是当我们使用的一些应用内编辑器没有真正具有标签替换功能时,对在原型设计阶段的代码库中的污染。)
诸如导入,导入,全局等内容的顺序。当它们混淆或乱序时,它会真正抛弃那些有大量导入的文件。
语句中的空格,特别是当人们使用制表符并尝试在var名称中跨越不同长度的行对齐赋值操作时(并且似乎没有办法说服那些执行它的人看起来像excel一块代码不整齐;))。
控制块内的间距,特别是当我在同一个流控制块中看到明显随机的间距,然后在对象内使用类似的方法间距时。在我开始读这该死的东西之前,我不得不编辑那些。
所以,那些是我的,以及我对PEP的“违反”背后的原因(有些是共享的,有些是同事不赞成的)。我非常好奇地阅读其他Pythonistas在这方面所做的和不做的事情。
答案 0 :(得分:47)
“每行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没有任何问题。该指南已经过时,并且会导致难以读取的难以阅读的代码。
答案 1 :(得分:39)
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))
同样地,令人讨厌的是,我以{+ 3}}格式化了它们通常由库本身格式化的:
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]])
答案 2 :(得分:20)
PEP8说
请注意,最重要的是,“”“结束多行文档字符串 应该在一条线上,并且最好在空格之后 行,例如:
"""Return a foobang Optional plotz says to frobnicate the bizbaz first. """
我觉得这很奇怪,因为它只是“无关的空白”,并且没有明显的原因,对开场报价的处理与报价不同。
理由是PEP 257:
Emacs,真的吗?每个人都应该做一些奇怪的事情来迎合特定编辑工具中特定命令的特性?BDFL建议在最后一段之间插入一个空行 在多行文档字符串及其结束引号中,放置结束 引用就行了。这样,Emacs的填充段落 可以使用命令。
我还认为将文档字符串的开头与引号(不是必需的,但推荐)放在同一行是很奇怪的,同时坚持将结束引用放在他们自己的行上。我认为这更符合逻辑,应该用于单行和多行文档字符串:
def foobang(bizbaz, plotz=None):
"""
Return a foobang
Optional plotz says to frobnicate the bizbaz first.
"""
if plotz is not None:
...
更新:粗体部分已被移除,现在它只是说“将关闭引号单独放在一行”,并且“摘要行可能与”打开引号或在下一行“。
答案 3 :(得分:17)
我不同意这一点:
- 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推荐的分组概念一致。
答案 4 :(得分:17)
标准至关重要,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)
答案 5 :(得分:6)
我公司的风格指南专门针对标签,而不是空格。 PEP 8暗示空间是可取的,但我们发现了相反的情况。我喜欢在VIM中看到代码缩进4个“空格”,同事喜欢Emacs中的8个“空格”。 使用标签可让我们设置编辑器以显示我们喜欢的代码。
请注意,在其他基于C语言中,缩进实际上只是格式化,但在Python 缩进是语法,因此我们认为indentation level 2
应由2
表示某事物(即标签)不是4
或8
某事物(即空格)。
缩进字符选择可能是最初的神圣火焰战争(甚至在VIM / Emacs火焰战争之前),所以我确实希望被修改为遗忘以表达对该主题的意见!
答案 6 :(得分:4)
我总是使用4个空格,我尝试每行最多使用79个字符,有时候不可能。 我过去也使用过像“import sys,os”这样的导入。 总的来说,我试着坚持PEP 8。
编辑:也可以使用:
def foobar():
"""
foobar
"""
用于文档
答案 7 :(得分:4)
多线条件等:PEP-8明确表示在二元运算符之后而不是之前打破。我担心我无法看到它的吸引力。对于我来说,在条件之前打破更有意义,因此在包裹/续行中,每个子行以条件开头:
if (condition1 \
or condition2 \
or condition3):
do_something()
可以看出,我还想为子线添加一个额外的缩进,以便它们在视觉上偏离下面的块。 PEP-8没有明确说明这一点(是吗?),但是这些例子的子行与开头的括号排成一行。
答案 8 :(得分:3)
PEP 8说:
是:
x = 1
y = 2
long_variable = 3
没有
x = 1
y = 2
long_variable = 3
我通常会遵循它,但为了更好的可读性,我有时会使用另一种变体:
x = 1
y = 2
long_variable = 3
答案 9 :(得分:2)
我的&#34;承认违规&#34;关于&#34;如果&#34;
PEP8说一行中没有多重声明,所以如果我们必须这样做:
if cond:
actions
...
但是当只有一个动作时,我更喜欢一条线, 例如我更喜欢:
if a == 0: b = 0
比:
if a == 0:
b = 0
答案 10 :(得分:2)
PEP 8的“问题”在于它倾向于个人偏好的领域,这些领域对大多数程序员来说都会受到相当大的情绪影响。
就我个人而言,camelCase vs下划线和列对齐指令是不变的问题。我在这里也看到了很多其他的回应,有时我会故意破坏PEP 8,因为在那种特殊情况下它只是“有意义”。
我的Python编程生涯中有一点我只是放弃并转向(使用)PEP 8.大多数项目相对容易,所以现在唯一的主要问题是列对齐。那个人太乱了,不服从(尽管我还是讨厌地做)。无论如何,由于我的“放弃”,我的代码现在对我的同事更具可读性 - 而且 - 令人惊讶的是:甚至对我来说(除了列对齐的东西:p)。
我还必须认识到PEP 8为python本身做了什么:在2.x(不兼容)和3.x(兼容)之间,我发现更容易“总是知道”特定函数的名称将是什么。 Python的“电池”现在分类得更好。
答案 11 :(得分:1)
当我写小脚本时,我经常只使用两个空格。
我总是对文档字符串使用相同的模式:
def function():
"""
Even if it's a single line.
"""
答案 12 :(得分:1)
我使用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对代码进行评级,并保持标准的编程方式,特别是在开发人员社区中。 =)
我希望它有所帮助。
答案 13 :(得分:1)
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视为普通字符串,任何其他字符串 value可能会导致以下文档字符串样式之一:
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-NN:
"""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.
"""