└── README.md
/README.md:
--------------------------------------------------------------------------------
1 | # PEP 8 - Python 代码风格指南
2 |
纷吾既有此内美兮,又重之以修能。 - 屈原《离骚》
3 |
4 | * [Introduction - 简介](#1)
5 | * [A Foolish Consistency is the Hobgoblin of Little Minds - 愚蠢的一致性是小心灵的大地精](#2)
6 | * [Code lay-out - 代码布局](#3)
7 | * [Indentation - 缩进](#3.1)
8 | * [Tabs or Spaces? - A 罩杯还是 E 罩杯 ?](#3.2)
9 | * [Maximum Line Length - 代码行最大长度](#3.3)
10 | * [Should a line break before or after a binary operator? - 在二元运算符之前还是之后断行?](#3.4)
11 | * [Blank Lines - 空行](#3.5)
12 | * [Source File Encoding - 源文件编码](#3.6)
13 | * [Imports - 模块导入](#3.7)
14 | * [Module level dunder names - 模块级 dunder 名称](#3.8)
15 | * [String Quotes - 字符串引号](#4)
16 | * [Whitespace in Expressions and Statements - 表达式和语句中的空格](#5)
17 | * [Pet Peeves - 心理藏的小烦恼](#5.1)
18 | * [Other Recommendations - 其他建议](#5.2)
19 | * [When to use trailing commas - 何时使用逗号结尾](#6)
20 | * [Comments - 注释](#7)
21 | * [Block Comments - 块注释](#7.1)
22 | * [Inline Comments - 行注释](#7.2)
23 | * [Documentation Strings - 文档字符串](#7.3)
24 | * [Naming Conventions - 命名约定](#8)
25 | * [Overriding Principle - 圣经戒律](#8.1)
26 | * [Descriptive: Naming Styles - 描述性: 命名风格](#8.2)
27 | * [Prescriptive: Naming Conventions - 规定性: 命名习惯](#8.3)
28 | * [Names to Avoid - 避免的命名](#8.3.1)
29 | * [Package and Module Names - 包和模块命名](#8.3.2)
30 | * [Class Names - 类名](#8.3.3)
31 | * [Type variable names - 类型变量名](#8.3.4)
32 | * [Exception Names - 异常名](#8.3.5)
33 | * [Global Variable Names - 全局变量名](#8.3.6)
34 | * [Function Names - 函数名](#8.3.7)
35 | * [Function and method arguments - 函数和方法参数](#8.3.8)
36 | * [Method Names and Instance Variables - 方法名和实例变量](#8.3.9)
37 | * [Constants - 常量](#8.3.10)
38 | * [Designing for inheritance - 继承设计](#8.3.11)
39 | * [Public and internal interfaces - 公共和内部接口](#8.3.12)
40 |
41 | 简介
42 |
43 | 很多项目都有自己独有的编码风格。如果和本文规则发生任何冲突,优先与项目级别的代码风格保持一致。
44 |
45 | 美其名曰:入乡随俗,Do what Romans do in Rome,到罗马咱就烤马肉吃。
46 |
47 | 愚蠢的一致性是小心灵的大地精
48 |
49 | 代码风格一致性当然重要,想象一下空姐的制服诱惑,是不是赏心悦目呢。但也要有自己的主观判断。
50 |
51 | 例如以下场景:
52 |
53 | 1、遵循此风格写的一小片代码看起来和项目内其他代码格格不入,看到就想抠出来喂猪,人人见而曰日之。
54 |
55 | 2、遵循此风格后和其他 python 版本不兼容,甚至出现错误,这就尴尬了。
56 |
57 | 3、遵循此风格中的某些条目使代码更不易读,简单说就是丑。
58 |
59 | 代码布局
60 |
61 | 缩进
62 |
63 | 一个缩进级别四个空格。
64 |
65 | * 连续行使用两种方式使封装元素成为一行:括号内垂直隐式连接 & 悬挂式缩进。 使用悬挂式缩进应该注意第一行不应该有参数,连续行要使用进一步的缩进来区分。
66 |
67 | ```Python
68 |
69 | 是:
70 |
71 | # 括号内隐式连接,垂直对齐
72 | foo = long_function_name(var_one, var_two,
73 | var_three, var_four)
74 |
75 | # 悬挂缩进,进一步缩进区分其他语句
76 | def long_function_name(
77 | var_one, var_two, var_three,
78 | var_four):
79 | print(var_one)
80 |
81 | # 悬挂缩进,一般是四个空格,但非必须
82 | foo = long_function_name(
83 | var_one, var_two,
84 | var_three, var_four)
85 |
86 | 否:
87 |
88 | # 括号内隐式连接,没有垂直对齐时,第一行的参数被禁止
89 | foo = long_function_name(var_one, var_two,
90 | var_three, var_four)
91 |
92 | # 悬挂缩进,需要进一步的缩进区分其他行
93 | def long_function_name(
94 | var_one, var_two, var_three,
95 | var_four):
96 | print(var_one)
97 | ```
98 |
99 | * 当 if 语句过长时,可选的处理方式,但不限于此:
100 |
101 | ```python
102 | # 不使用额外缩进
103 | if (this_is_one_thing and
104 | that_is_another_thing):
105 | do_something()
106 |
107 | # 增加注释区分,支持语法高亮
108 | if (this_is_one_thing and
109 | that_is_another_thing):
110 | # Since both conditions are true, we can frobnicate.
111 | do_something()
112 |
113 | # 条件连续行额外缩进
114 | if (this_is_one_thing
115 | and that_is_another_thing):
116 | do_something()
117 | ```
118 |
119 | * 当闭环括号内元素跨行时,可以采用以下方式。
120 |
121 | ```Python
122 | my_list = [
123 | 1, 2, 3,
124 | 4, 5, 6,
125 | ]
126 | result = some_function_that_takes_arguments(
127 | 'a', 'b', 'c',
128 | 'd', 'e', 'f',
129 | )
130 | ```
131 | 或者
132 | ```python
133 | my_list = [
134 | 1, 2, 3,
135 | 4, 5, 6,
136 | ]
137 | result = some_function_that_takes_arguments(
138 | 'a', 'b', 'c',
139 | 'd', 'e', 'f',
140 | )
141 | ```
142 |
143 | A 罩杯还是 E 罩杯 ?
144 |
145 | A 罩杯。
146 |
147 | Python 3 不允许 tab 和 space 混用,同时混用了 tab 和 space 的 Python 2 代码应该被转换为仅使用 space。
148 |
149 | 代码行最大长度
150 |
151 | 将所有行限制为最多79个字符。
152 |
153 | 对于具有较少结构限制(文档字符串或注释)的长文本块,行长度应限制为72个字符。
154 |
155 | 当然了,不要问为啥非得是 79,72。我们要兼顾非洲大陆人民的生活。代码是全世界的。
156 |
157 | 反斜杠有时可能仍然要用。 例如,又多又长的 with - 语句不能使用隐式连接,这时反斜杠是可以接受的:
158 |
159 | ```Python
160 | with open('/path/to/some/file/you/want/to/read') as file_1, \
161 | open('/path/to/some/file/being/written', 'w') as file_2:
162 | file_2.write(file_1.read())
163 | ```
164 |
165 | assert 语句也是如此。
166 |
167 | 在二元运算符之前还是之后断行?
168 |
169 | 算法和程序设计技术先驱,计算机排版系统 TEX 和 METAFONT 的发明者 Donald Knuth,推荐使用以下形式:
170 |
171 | ```Python
172 | # 是: easy to match operators with operands
173 | income = (gross_wages
174 | + taxable_interest
175 | + (dividends - qualified_dividends)
176 | - ira_deduction
177 | - student_loan_interest)
178 | ```
179 |
180 | 只要保持本地一致性,在二元运算符之前和之后断开都是允许的,但是新的 Python 代码推荐使用 Knuth 形式。
181 |
182 | 空行
183 |
184 | 顶层函数和类定义间使用两个空行。
185 |
186 | 类内方法定义间使用一个空行。
187 |
188 | 不同函数组之间使用两个空行隔离。
189 |
190 | 总之,空行的作用就是隔离不同函数类等,使层次分明。
191 |
192 | 源文件编码
193 |
194 | Python 2 默认ASCII,Python 3 默认UTF-8。
195 |
196 | 使用 ASCII 的 Python 2 源文件或使用 UTF-8 的 Python 3 源文件不应该有编码声明。
197 |
198 | 源文件最好只使用 ASCII 字符,即使是蹩脚的 Chinglish 亦可,家和万事兴。
199 |
200 | 模块导入
201 |
202 | ```Python
203 | 是:
204 | from subprocess import Popen, PIPE
205 | import os
206 | import sys
207 |
208 | 否:
209 | import sys, os
210 | ```
211 |
212 | 模块导入总是位于文件顶部,在模块注释和文档字符串之后,模块全局变量和常量之前。
213 |
214 | 导入应该按照以下顺序分组,不同组间用空行隔离。
215 |
216 | * 标准库 imports
217 | * 相关第三方 imports
218 | * 本地特定应用/库 imports
219 |
220 | 推荐使用绝对导入,标准库代码应总是使用绝对导入。
221 |
222 | ```Python
223 | import mypkg.sibling
224 | from mypkg import sibling
225 | from mypkg.sibling import example
226 | ```
227 |
228 | 在包结构比较复杂时,可以使用相对导入。
229 |
230 | ```Python
231 | from . import sibling
232 | from .sibling import example
233 | ```
234 |
235 | 在 Python 3 中,相对导入已经被删除,禁止使用。
236 |
237 | 类导入:
238 |
239 | ```Python
240 | from myclass import MyClass
241 | from foo.bar.yourclass import YourClass
242 | ```
243 |
244 | 如果这种方式导致了本地命名冲突,可以使用以下方式:
245 |
246 | ```Python
247 | import myclass
248 | import foo.bar.yourclass
249 | ```
250 |
251 | 然后使用 myclass.MyClass 和 foo.bar.yourclass.YourClass。
252 |
253 | 请不要使用以下方式:
254 |
255 | ```Python
256 | from import *
257 | ```
258 |
259 | 模块级别 dunder 名称
260 |
261 | 模块级别 “dunders”(即具有两个前导和两个后缀下划线的名称),例如 \_\_all\_\_,\_\_author\_\_,\_\_version\_\_ 等应放在模块 docstring 之后,但在任何 import 语句之前,但是除了 \_\_future\_\_ 导入。 Python 强制 future-imports 必须在除了 docstrings 之外的任何其他代码之前出现在模块中。
262 | 例如:
263 |
264 | ```Python
265 | """This is the example module.
266 |
267 | This module does stuff.
268 | """
269 |
270 | from __future__ import barry_as_FLUFL
271 |
272 | __all__ = ['a', 'b', 'c']
273 | __version__ = '0.1'
274 | __author__ = 'Cardinal Biggles'
275 |
276 | import os
277 | import sys
278 | ```
279 |
280 | 字符串引号
281 |
282 | 在 Python 中,单引号和双引号是等价的,只需要坚持使用一种并保持一致即可。
283 |
284 | 在双引号中使用单引号,单引号中使用双引号。三引号中使用双引号。
285 |
286 | 表达式和语句中的空格
287 |
288 | 心理藏的小烦恼
289 |
290 | 在以下场景避免不必要的空格
291 |
292 | ```Python
293 | 是: spam(ham[1], {eggs: 2})
294 | 否: spam( ham[ 1 ], { eggs: 2 } )
295 |
296 | 是: foo = (0,)
297 | 否: bar = (0, )
298 |
299 | 是: if x == 4: print x, y; x, y = y, x
300 | 否: if x == 4 : print x , y ; x , y = y , x
301 |
302 | 是:
303 | ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:]
304 | ham[lower:upper], ham[lower:upper:], ham[lower::step]
305 | ham[lower+offset : upper+offset]
306 | ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
307 | ham[lower + offset : upper + offset]
308 |
309 | 否:
310 | ham[lower + offset:upper + offset]
311 | ham[1: 9], ham[1 :9], ham[1:9 :3]
312 | ham[lower : : upper]
313 | ham[ : upper]
314 |
315 | 是: spam(1)
316 | 否: spam (1)
317 |
318 | 是: dct['key'] = lst[index]
319 | 否: dct ['key'] = lst [index]
320 |
321 | 是:
322 | x = 1
323 | y = 2
324 | long_variable = 3
325 |
326 | 否:
327 | x = 1
328 | y = 2
329 | long_variable = 3
330 |
331 | ```
332 |
333 | 其他建议
334 |
335 | 在任何地方避免使用尾随空格。
336 |
337 | 在二元运算符周围使用空格:
338 |
339 | ```python
340 | 是:
341 |
342 | i = i + 1
343 | submitted += 1
344 | x = x*2 - 1
345 | hypot2 = x*x + y*y
346 | c = (a+b) * (a-b)
347 |
348 | 否:
349 |
350 | i=i+1
351 | submitted +=1
352 | x = x * 2 - 1
353 | hypot2 = x * x + y * y
354 | c = (a + b) * (a - b)
355 | ```
356 | 表示关键字参数或默认参数值时,不要使用空格:
357 |
358 | ```python
359 | 是:
360 |
361 | def complex(real, imag=0.0):
362 | return magic(r=real, i=imag)
363 | 否:
364 |
365 | def complex(real, imag = 0.0):
366 | return magic(r = real, i = imag)
367 | ```
368 | 函数注解的场景:
369 |
370 | ```python
371 | 是:
372 |
373 | def munge(input: AnyStr): ...
374 | def munge() -> AnyStr: ...
375 |
376 | 否:
377 |
378 | def munge(input:AnyStr): ...
379 | def munge()->PosInt: ...
380 | ```
381 |
382 | 当参数注释和默认值共存时:
383 |
384 | ```python
385 | 是:
386 |
387 | def munge(sep: AnyStr = None): ...
388 | def munge(input: AnyStr, sep: AnyStr = None, limit=1000): ...
389 |
390 | 否:
391 |
392 | def munge(input: AnyStr=None): ...
393 | def munge(input: AnyStr, limit = 1000): ...
394 | ```
395 |
396 | 同行多语句不建议使用:
397 |
398 | ```python
399 | 是:
400 |
401 | if foo == 'blah':
402 | do_blah_thing()
403 | do_one()
404 | do_two()
405 | do_three()
406 |
407 | Rather not:
408 |
409 | if foo == 'blah': do_blah_thing()
410 | do_one(); do_two(); do_three()
411 | ```
412 |
413 | 下面这种丑就不多说了:
414 |
415 | ```python
416 | Rather not:
417 |
418 | if foo == 'blah': do_blah_thing()
419 | for x in lst: total += x
420 | while t < 10: t = delay()
421 |
422 | Definitely not:
423 |
424 | if foo == 'blah': do_blah_thing()
425 | else: do_non_blah_thing()
426 |
427 | try: something()
428 | finally: cleanup()
429 |
430 | do_one(); do_two(); do_three(long, argument,
431 | list, like, this)
432 |
433 | if foo == 'blah': one(); two(); three()
434 | ```
435 |
436 | 何时使用逗号结尾
437 |
438 | 单元素元组强制使用逗号:
439 |
440 | ```python
441 | 是:
442 |
443 | FILES = ('setup.cfg',)
444 |
445 | OK, but confusing:
446 |
447 | FILES = 'setup.cfg',
448 | ```
449 | 当使用版本控制系统时,一组希望后续扩展的值/参数/改善的条目使用以下形式:
450 | ```python
451 | 是:
452 |
453 | FILES = [
454 | 'setup.cfg',
455 | 'tox.ini',
456 | ]
457 | initialize(FILES,
458 | error=True,
459 | )
460 | 否:
461 |
462 | FILES = ['setup.cfg', 'tox.ini',]
463 | initialize(FILES, error=True,)
464 | ```
465 |
466 | 注释
467 |
468 | 糟糕的注释不如没有注释,一定要用 English 注释。
469 |
470 | 块注释
471 |
472 | 同等级别的一块代码的注释,块注释内每行注释以 \# 开头,内部注释段落之间使用以 \# 开头的空行注释隔开。
473 |
474 | 行注释
475 |
476 | 行注释和代码声明间至少间隔两个空格,不要使用无聊的行注释,例如:
477 |
478 | ```python
479 | Don't do this:
480 |
481 | x = x + 1 # Increment x
482 |
483 | But sometimes, this is useful:
484 |
485 | x = x + 1 # Compensate for border
486 | ```
487 |
488 | 文档字符串
489 |
490 | 为所有公共模块,函数,类和方法编写文档字符串。 对于非公共方法,文本字符串不是必需的,但应该有一个描述该方法的注释。例如:
491 | ```python
492 | """Return a foobang
493 |
494 | Optional plotz says to frobnicate the bizbaz first.
495 | """
496 |
497 | """only one single docstring line"""
498 | ```
499 |
500 | 注意当注释为多行时,最终的 """ 单独起一行。
501 |
502 |
503 | 命名约定
504 |
505 | 圣经戒律
506 |
507 | 对用户可见的公共 API 部分的命名应该遵从反应如何使用而不是怎么实现。
508 |
509 | 描述性: 命名风格
510 |
511 | 以下命名风格通常区分彼此使用:
512 |
513 | * b (单个小写字母)
514 |
515 | * B (单个大写字母)
516 |
517 | * lowercase(小写)
518 |
519 | * lower\_case\_with_underscores(带下划线的小写)
520 |
521 | * UPPERCASE(大写)
522 |
523 | * UPPER\_CASE\_WITH\_UNDERSCORES(带下划线的大写)
524 |
525 | * CapitalizedWords(驼峰式,蒙古包式 whatever.)
526 |
527 | Note: 使用驼峰式时,缩写全部大写,例如:HTTPServerError 好于 HttpServerError
528 |
529 | * mixedCase (乌鬼头)
530 |
531 | * Capitalized_Words_With_Underscores (丑!不解释!)
532 |
533 | * \_single\_leading\_underscore : 弱地 "内部使用" 指示器. 例如,from M import * 不会导入下划线开头的对象
534 |
535 | * single\_trailing\_underscore\_ : 用来避免和 python 关键字冲突,例如:
536 | ```python
537 | Tkinter.Toplevel(master, class_='ClassName')
538 | ```
539 | * \_\_double\_leading_underscore : 当对类属性命名时,调用名改变 (在 FooBar 类内,\_\_boo 变成了 \_FooBar\_\_boo;后面有介绍)
540 |
541 | * \_\_double\_leading\_and\_trailing\_underscore\_\_ : "魔幻的" 对象或属性,只生存于用户控制的命名空间。例如, \_\_init\_\_ ,\_\_import\_\_ 或 \_\_file\_\_ 。千万不要臆造这种命名; only use them as documented.
542 |
543 | 规定性: 命名习惯
544 |
545 | 避免的命名
546 |
547 | 一定不要使用 l(唉欧儿) O(偶) I(艾) 作为单字符变量命名,在某些字体中,这些字母和数字 1 0 无法区分。
548 |
549 | 包和模块名
550 |
551 | 模块应该使用简短并且全小写的命名,下划线也可以使用以提升可读性。
552 |
553 | Python 包也应该使用简短的全小写名称,尽管不鼓励使用下划线。
554 |
555 | 当 C/C++ 编写的扩展模块伴随一个提供更高级别接口的 python 模块时,C/C++ 模块命名应该以下划线开头(例如,\_socket)。
556 |
557 | 类名
558 |
559 | 类名通常使用驼峰式命名习惯。
560 |
561 | 在类的接口有文档说明,并且主要用于 callable 的情况下,类都是 callable 的,call 一个类将返回一个新的类实例,例如 instance = Class()。如果类实现了 \_\_call\_\_() 函数,那么类实例也将是 callable 的,类的命名也可以使用函数命名习惯。
562 |
563 | 对于 builtin 函数的命名习惯,可以通过 dir(\_\_builtins\_\_)
查看系统函数命名样例。注意区分普通命名,异常名命名和 builtin 常量。
564 |
565 | 类型变量名
566 |
567 | 相对于短名称如:T,AnyStr,Num,类型变量使用驼峰式命名习惯较好。另外建议在变量名前添加 \_co 或 \_contra 前缀响应的声明 covariant 或 contravariant 行为。例如:
568 |
569 | ```python
570 | from typing import TypeVar
571 |
572 | VT_co = TypeVar('VT_co', covariant=True)
573 | KT_contra = TypeVar('KT_contra', contravariant=True)
574 | ```
575 |
576 | 异常名
577 |
578 | 异常应该是类,所以可以使用类命名习惯,但是,如果异常是个错误类,一般加上 "Error" 后缀。
579 |
580 | 全局变量名
581 |
582 | 我们假设这些全局变量只在一个模块内使用,这样的话和函数的命名习惯是一样的。
583 |
584 | 设计为通过 from M import *
导入的类应该使用 \_\_all\_\_ 机制避免导出全局变量,或者可以使用老式的习惯,给这些全局变量名加上下划线作为前缀(表示这是非公有变量)。
585 |
586 |
587 | 函数名
588 |
589 | 例如,func
or func_write_to_file
590 |
591 | 为了向后兼容性,也可以使用 mixedCase 式命名风格。
592 |
593 | 函数和方法参数
594 |
595 | 实例方法第一个入参一定要是 self。
596 |
597 | 类方法第一个入参一定要是 cls。
598 |
599 | 如果函数入参名和保留关键字冲突,则后缀下划线好过缩写或者糟糕的拼写。
600 |
601 | 例如,class_ 好过 clss。
602 |
603 | 方法名和实例变量
604 |
605 | 使用函数命名风格即可。如果希望是私有方法或实例变量,则前缀下划线。
606 |
607 | 为避免和子类的命名冲突,请使用双下划线前缀命名。
608 |
609 | 如果类 Foo 有一个属性变量 __a,那么通过 Foo.__a 是不能被访问的。当然,固执的用户仍然可以通过 Foo._Foo__a 访问),一般来说,双下划线前缀只是在避免子类属性命名冲突的场景下使用。
610 |
611 | 常量
612 |
613 | 常量一般定义在模块级别。命名风格如:MAX_OVERFLOW 或 TOTAL 。
614 |
615 | 继承设计
616 |
617 | 经常去思考类方法和实例变量(属性)应该是公有的还是非公有的(严格意义上,python 没有私有变量)。如果不确定,那就设置成非公有的。
618 |
619 | 另一类属性类别是子类 API 的一部分,(在其他语言中称"protected")。有些类天生就是被设计为用来继承的,当设计这种类时,注意哪些属性是公有的,哪些是子类 API 的一部分,哪些是只在基类中使用的。
620 |
621 | 神谕的指导:
622 |
623 | * 公有实例变量不应该有前缀下划线。
624 | * 公有实例变量和保留关键字冲突时,变量名加前缀下划线避免,这比使用缩写和其他糟糕的拼写要好(除了 'cls',当一个变量或入参确定是一个类,特别是作为类方法的第一个入参时,'cls' 更惹人喜爱)。
625 | * 对于简单的公有数据属性,不要使用复杂的存取函数,直接暴露属性名。
626 | * 如果设计继承基类时,不希望子类访问的属性加双下划线前缀。
627 |
628 | 公共和内部接口
629 |
630 | 文档说明的接口一般认为是公共接口,除非文档明确声明为临时或内部接口(为了兼容性等其他原因),所有非文档说明的接口一般为内部接口。
631 |
632 | 模块应该使用 \_\_all\_\_ 属性明确声明公共 API 名,如果 \_\_all\_\_ 为空,则表明模块没有公共 API。
633 |
634 | 尽管使用了 \_\_all\_\_ 属性,内部接口(packages, modules, classes, functions, attributes or other names)仍然需要使用前缀下划线。
635 |
636 | 如果包含的任何一个命名空间(package, module or class)是内部的,那么这个接口也被认为是内部接口。
637 |
638 | 导入名应该总是被视为实现细节。其他导入模块一定不能依赖对此导入名的间接访问,除非它们是包含模块 API 的显式文档说明的部分,例如 os.path 或者一个 package 向子模块暴露函数的 \_\_init\_\_ 模块。
639 |
640 | 编码建议
641 |
642 | * 代码不应该以一种不利于其他 python 实现(PyPy, Jython, IronPython, Cython, Psyco 诸如此类)的方式编写。 例如:不要使用 a += b 或 a = a + b 来实现就地字符串连接,在库的性能敏感部分,应该使用 ''.join() 的形式,这就能保证在不同的 python 实现中,连接动作可以在线性时间内完成。
643 |
644 | * 和例如 None 这类 singleton 的比较,应该使用 is 或 is not 而不是 ==。另外,小心使用 if x
如果你的本意是 if x is not None
,如果 x 是个布尔变量值 false,那可就完蛋了。
645 |
646 | * 尽管功能相同,从可读性上考虑:
647 |
648 | ```python
649 | 是:
650 |
651 | if foo is not None:
652 |
653 | 否:
654 |
655 | if not foo is None:
656 | ```
657 | * 当使用 rich comparisons 实现排序操作时,最好是实现所有六种操作(\_\_eq\_\_,\_\_ne\_\_, \_\_lt\_\_, \_\_le\_\_, \_\_gt\_\_, \_\_ge\_\_)而不要依赖其他的代码去单独实现某一类比较。为了减少劳动,functools.total_ordering() decorator 提供了一个生成缺失比较方法的工具。
658 |
659 | * 使用 def 语句而不要使用赋值语句去直接绑定一个 lambda 表达式到标识符上:
660 |
661 | ```python
662 | 是:
663 |
664 | def f(x): return 2*x
665 |
666 | 否:
667 |
668 | f = lambda x: 2*x
669 | ```
670 |
671 | 赋值语句的使用消除了 lambda 表达式相对于显式 def 语句的唯一好处,那就是它能够嵌入到一个更大的表达式里面。
672 |
673 | * 捕获的异常要说明 "错误出在哪里了 ?" 而不是仅仅说明 "哎呀!出问题了!"。
674 |
675 | * 正确使用异常链接。在 Python 3 中,应该使用 "raise X from Y" 来表示显式替换并且不会丢失原始追溯。
676 |
677 | 当有意替换一个内部异常(Python 2: "raise X", Python 3.3+: raise X from Non)时,请确保将相关的详细信息转移到新的异常(例如,将 KeyError 转换为 AttributeError 时保留属性名称,或将原始异常的文本嵌入到新的异常消息中)。
678 |
679 | * 当在 Python 2 中抛出异常时,使用 raise ValueError('message')
而不是老式的 raise ValueError, 'message'
,后者已经在 Python 3 中废弃。由于使用了括号,可以避免行连续符的使用。
680 |
681 | * 当捕获异常时,尽可能提及具体的异常而不是使用一个赤裸裸的 except 子句。一个裸露的 except: 子句将捕获 SystemExit 和 KeyboardInterrupt 异常,这样的话就难于使用 control-c 中断程序,并可能掩盖其他问题。如果想要捕获标志程序错误的所有异常的话,用 except Exception:(裸露的 except 子句等同于 except BaseException:):
682 |
683 | ```python
684 | try:
685 | import platform_specific_module
686 | except ImportError:
687 | platform_specific_module = None
688 | ```
689 |
690 |
691 |
692 | 一个很好的经验法则是将裸露的 except 子句仅用于以下两种情况:
693 |
694 | 1、If the exception handler will be printing out or logging the traceback; at least the user will be aware that an error has occurred.
695 |
696 | 2、If the code needs to do some cleanup work, but then lets the exception propagate upwards with raise . try...finally can be a better way to handle this case.
697 |
698 |
699 |
700 | * 当对捕获的异常重命名时,使用 2.6 版本引入的语法:
701 |
702 | ```python
703 | try:
704 | process_data()
705 | except Exception as exc:
706 | raise DataProcessingFailedError(str(exc))
707 | ```
708 |
709 | * 当捕获操作系统错误时,相对于内置的 errno 值,最好是使用 Python 3.3 中介绍的显式异常层次结构。
710 |
711 | * 对于所有的 try/except 子句,将 try 子句限制为必需的绝对最小代码量避免隐藏 bug:
712 |
713 | ```python
714 | 是:
715 |
716 | try:
717 | value = collection[key]
718 | except KeyError:
719 | return key_not_found(key)
720 | else:
721 | return handle_value(value)
722 |
723 | 否:
724 |
725 | try:
726 | # Too broad!
727 | return handle_value(collection[key])
728 | except KeyError:
729 | # Will also catch KeyError raised by handle_value()
730 | return key_not_found(key)
731 | ```
732 |
733 | * 特定代码块的本地资源使用 with 语句确保使用后立即释放,不能自动释放的使用 try/finally 也可以。
734 |
735 | * 除了申请和释放资源,任何时候都应该使用单独的函数和方法调用 Context managers,例如:
736 |
737 | ```python
738 | 是:
739 |
740 | with conn.begin_transaction():
741 | do_stuff_in_transaction(conn)
742 |
743 | 否:
744 |
745 | with conn:
746 | do_stuff_in_transaction(conn)
747 | ```
748 |
749 | * 函数返回语句要一致。在一个函数内的所有返回语句要么都返回一个表达式,要么都不返回。如果任何一个返回语句返回了表达式,那么其他任何没有返回值的语句应该明确声明为 return None。在函数结束部分必须出现返回语句:
750 | ```python
751 | 是:
752 |
753 | def foo(x):
754 | if x >= 0:
755 | return math.sqrt(x)
756 | else:
757 | return None
758 |
759 | def bar(x):
760 | if x < 0:
761 | return None
762 | return math.sqrt(x)
763 |
764 | 否:
765 |
766 | def foo(x):
767 | if x >= 0:
768 | return math.sqrt(x)
769 |
770 | def bar(x):
771 | if x < 0:
772 | return
773 | return math.sqrt(x)
774 | ```
775 |
776 | * 相对于 string 模块,使用 string 方法要快的多并且与 unicode strings 共享相同的 API。当然了,除了需要考虑 2.0 版本之前 python 代码向后兼容性的情况。
777 |
778 | * 使用 ''.startswith() 和 ''.endswith() 而不是字符串切片来检查前缀或后缀,例如:
779 |
780 | ```python
781 | 是: if foo.startswith('bar'):
782 | 否: if foo[:3] == 'bar':
783 | ```
784 |
785 | * 对象类型比较应该使用isinstance() 而不是直接比较:
786 |
787 | ```python
788 | 是: if isinstance(obj, int):
789 | 否: if type(obj) is type(1):
790 | ```
791 |
792 | 当检查一个对象是否为字符串时,一定要注意这个对象也可能是 unicode 字符串!在 Python 2 中,string 和 unicode 拥有一个公共基类 basestring,因此可以这么的:
793 |
794 | ```python
795 | if isinstance(obj, basestring):
796 | ```
797 |
798 | 在 Python 3 中,unicode 和 basestring 已然不复存在(there's only str),并且 bytes object 也不再视为一种 string 了,而是一个整形序列。
799 |
800 | * 对于序列(字符串,列表,元组)的判空操作:
801 | ```python
802 | 是:
803 | if not seq:
804 | if seq:
805 |
806 | 否:
807 | if len(seq):
808 | if not len(seq):
809 | ```
810 |
811 | * 不要使用尾随空格。
812 |
813 | * 不要使用 == 验证布尔值为 Ture 或 False:
814 |
815 | ```python
816 | 是:
817 | if greeting:
818 | 否:
819 | if greeting == True:
820 | 虾扯蛋:
821 | if greeting is True:
822 | ```
823 |
824 | ## 别扯了,再扯蛋都碎了 。=_=#
825 |
--------------------------------------------------------------------------------