└── 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 | --------------------------------------------------------------------------------