Python风格指南,Python语言专业

  • Python是一种对代码风格很注重的言语,从缩进就能观望这点,Python强调易于领悟。近来在担负代码重构的做事,为了统一大家的代码风格,制订规范,学习了弹指间网上这份谷歌的Python风格指南。

  • 初稿地址:
    http://google-styleguide.googlecode.com/svn/trunk/pyguide.html

前边写代码感觉一向缺点和失误一定的科班,所以整理了部分Python的言语专业地点的东东,这些来自google宣布的开源项目风格指南-Python语言专业。

背景

Python 是
谷歌主要的脚本语言。那本风格指南首要涵盖的是对准python的编制程序准则。
为帮助读者能够将代码准确格式化,大家提供了针对性 Vim的配备文件
。对于Emacs用户,保持暗中同意设置即可。

一 、对您的代码运营pylint

Python语言专业

定义:

pylint是2个在Python源代码中查找bug的工具.
对于C和C++那样的不那么动态的(译者注: 原文是less dynamic)语言,
那一个bug平常由编译器来捕获. 由于Python的动态脾性, 有些警告恐怕不对.
但是伪告警应该很少.

pylint

Tip
对您的代码运维pylint

定义:
pylint是贰个在Python源代码中查找bug的工具.
对于C和C++这样的不那么动态的(译者注: 原文是less dynamic)语言,
那个bug经常由编写翻译器来捕获. 由于Python的动态性情, 有个别警告只怕不对.
不过伪告警应该很少.
优点:
能够捕获容易忽视的不当, 例如输入错误, 使用未赋值的变量等.
缺点:
pylint不完美. 要选择其优势, 大家有时候侯须求: a) 围绕着它来写代码 b)
抑制其报告警方 c) 创新它, 只怕d) 忽略它.
结论:
管教对您的代码运维pylint.抑制不可信的警示,以便能够将其余警告暴流露来。
您能够由此设置3个行注释来防止告警. 例如:

dict = 'something awful'  # Bad Idea... pylint: disable=redefined-builtin

pylint警告是以贰个数字编号(如 C0112 )和叁个标记名(如 empty-docstring
)来标识的. 在编排新代码或更新已有代码时对报告警方进行医疗,
推荐应用标志名来标识.

一旦警告的号子名不够见名知意,那么请对其扩大三个详尽分解。

选用那种抑制方式的功利是大家能够轻松查找抑制并想起它们.

您能够采纳命令 pylint --list-msgs 来获取pylint告警列表. 你可以行义务令
pylint --help-msg=C6409 , 以取得有关特定消息的越多新闻.

相相比于事先运用的 pylint: disable-msg , 本文推荐使用
pylint: disable .

要防止”参数未利用”告警, 你能够用””作为参数标识符,
恐怕在参数名前加”unused
”. 碰到不可能更改参数名的图景,
你能够透过在函数开首”提到”它们来排除告警. 例如:

    def foo(a, unused_b, unused_c, d=None, e=None):
        _ = d, e
        return a

优点:

能够捕获简单忽视的谬误, 例如输入错误, 使用未赋值的变量等.

导入

Tip
仅对包和模块使用导入

定义:
模块间共享代码的选定机制.
优点:
命名空间管理约定十一分简单. 各类标识符的源都用一种同等的主意提醒.
x.Obj表示Obj对象定义在模块x中.
缺点:
模块名仍恐怕争执. 有些模块名太长, 不太方便.
结论:
使用 import x 来导入包和模块.

使用 from x import y , 在那之中x是包前缀, y是不带前缀的模块名.

使用 from x import y as z, 假若七个要导入的模块都叫做z可能y太长了.

例如, 模块 sound.effects.echo 能够用如下格局导入:

    from sound.effects import echo
    ...
    echo.EchoFilter(input, output, delay=0.7, atten=4)

导入时决不使用相对名称. 纵然模块在同多个包中, 也要动用完整包名.
那能帮忙你避免无意间导入四个包四回.

缺点:

pylint不完美. 要采纳其优势, 我们偶尔侯必要: a) 围绕着它来写代码 b)
抑制其报告警方 c) 立异它, 大概d) 忽略它.

Tip
运用模块的整个径名来导入每一种模块

优点:
防止模块名抵触. 查找包更不难.
缺点:
布置代码变难, 因为您不能够不复制包层次.
结论:
装有的新代码都应有用全部包名来导入种种模块.

相应像下边那样导入:

# Reference in code with complete name.
import sound.effects.echo

# Reference in code with just module name (preferred).
from sound.effects import echo

结论:

保障对您的代码运转pylint.抑制不标准的警戒,以便能够将其余警告暴暴露来。

你能够经过设置三个行注释来抑制告警. 例如:

dict = 'something awful'  # Bad Idea... pylint: disable=redefined-builtin

pylint警告是以三个数字编号(如 C0112 )和三个标记名(如 empty-docstring
)来标识的. 在编排新代码或更新已有代码时对报告警方实行医疗,
推荐使用标志名来标识.

万一警告的号子名不够见名知意,那么请对其扩张四个详实表明。

接纳那种抑制格局的好处是我们能够轻松查找抑制并想起它们.

你能够使用命令 pylint –list-msgs 来博取pylint告警列表. 你能够应用命令
pylint –help-msg=C6409 , 以取得有关特定新闻的越多新闻.

绝相比较于事先运用的 pylint: disable-msg , 本文推荐使用 pylint: disable .

要遏制”参数未采纳”告警, 你能够用””作为参数标识符,
或然在参数名前加”unused
”. 际遇无法改变参数名的图景,
你能够因此在函数起始”提到”它们来解决告警. 例如:

def foo(a, unused_b, unused_c, d=None, e=None):
    _ = d, e
    return a

异常

Tip
允许采用尤其, 但必须小心

定义:
极度是一种跳出代码块的平常化控制流来处理错误只怕其他相当条件的方式.
优点:
正规操作代码的控制流不会和错误处理代码混在一起. 当某种条件发出时,
它也允许控制流跳过四个框架. 例如, 一步跳出N个嵌套的函数,
而不必继续执行错误的代码.
缺点:
大概会导致令人疑忌的控制流. 调用库时便于失去错误情形.
结论:
充裕必须遵守特定条件:

  1. 像这么触发分外: raise MyException("Error message") 或者
    raise MyException . 不要使用五个参数的款型(
    raise MyException, "Error message" )恐怕过时的字符串分外(
    raise "Error message" ).

  2. 模块或包应该定义自身的特定域的非凡基类,
    那些基类应该从内建的Exception类继承. 模块的特别基类应该称为”Error”.

    class Error(Exception):
        pass
  1. 永恒不要采取 except: 语句来捕获全数特别, 也不用捕获 Exception
    或者 StandardError , 除非你打算重新触发该尤其,
    或然你已经在近期线程的最外层(记得照旧要打字与印刷一条错误新闻).
    在十一分那地方, Python格外宽容, except:
    真的会捕获包罗Python语法错误在内的别样错误. 使用 except:
    很简单隐藏真正的bug.

  2. 尽量收缩try/except块中的代码量. try块的体量越大,
    期望之外的要命就越容易被触发. 那种场合下,
    try/except块将藏匿真正的错误.

  3. 应用finally子句来施行那个无论try块中有没有越发都应有被实践的代码.
    那对于清理财富平日很有用, 例如关闭文件.
    当捕获非常时, 使用 as 而毫无用逗号. 例如

try:
    raise Error
except Error as error:
    pass

② 、仅对包和模块使用导入

全局变量

Tip
幸免全局变量

定义:
概念在模块级的变量.
优点:
有时有用.
缺点:
导入时或然改变模块行为, 因为导入模块时会对模块级变量赋值.
结论:
制止选择全局变量, 用类变量来代替. 但也有一对分化:

  1. 剧本的暗中认可选项.
  2. 模块级常量. 例如: PI = 3.14159. 常量应该全大写, 用下划线连接.
  3. 奇迹用全局变量来缓存值可能当作函数重返值很有用.
  4. 设若供给, 全局变量应该仅在模块内部可用,
    并通过模块级的公家函数来访问.

定义:

模块间共享代码的录取机制.

嵌套 局部 内部类或函数

Tip
勉励使用嵌套/本地/内部类或函数

定义:
类能够定义在艺术, 函数恐怕类中. 函数能够定义在格局或函数中.
封闭区间中定义的变量对嵌套函数是只读的.
优点:
同意定义仅用于有效限制的工具类和函数.
缺点:
嵌套类或局项指标实例无法连串化(pickled).
结论:
推荐介绍使用.

优点:

命名空间管理约定13分简单. 每一个标识符的源都用一种同等的法子提示.
x.Obj表示Obj对象定义在模块x中.

列表推导 List Comprehensions

Tip
能够在简易情形下选拔

定义:
列表推导(list comprehensions)与生成器表明式(generator
expression)提供了一种精简高效的方法来创建列表和迭代器, 而不必借助map(),
filter(), 或许lambda.
优点:
不难的列表推导能够比其余的列表创制方法尤其清晰简单.
生成器表明式能够12分飞快, 因为它们制止了创制整个列表.
缺点:
复杂的列表推导只怕生成器表明式恐怕麻烦阅读.
结论:
适用于不难情况. 每一种部分应该单独置于一行: 映射表明式, for语句,
过滤器表明式. 禁止多重for语句或过滤器表明式. 复杂意况下或许利用循环.

Yes:
  result = []
  for x in range(10):
      for y in range(5):
          if x * y > 10:
              result.append((x, y))

  for x in xrange(5):
      for y in xrange(5):
          if x != y:
              for z in xrange(5):
                  if y != z:
                      yield (x, y, z)

  return ((x, complicated_transform(x))
          for x in long_generator_function(parameter)
          if x is not None)

  squares = [x * x for x in range(10)]

  eat(jelly_bean for jelly_bean in jelly_beans
      if jelly_bean.color == 'black')

No:
  result = [(x, y) for x in range(10) for y in range(5) if x * y > 10]

  return ((x, y, z)
          for x in xrange(5)
          for y in xrange(5)
          if x != y
          for z in xrange(5)
          if y != z)

缺点:

模块名仍只怕争辩. 有个别模块名太长, 不太方便.

暗许迭代器和操作符

Tip
倘诺类型帮助, 就采纳暗中同意迭代器和操作符. 比如列表, 字典及文件等.

定义:
容器类型, 像字典和列表, 定义了默许的迭代器和涉及测试操作符(in和not in)
优点:
默许操作符和迭代器不难便捷, 它们一贯表述了操作, 没有额外的办法调用.
使用暗中认可操作符的函数是通用的. 它能够用于援救该操作的任何类型.
缺点:
您没办法通过阅读格局名来分别对象的连串(例如, has_key()意味着字典).
不过那也是优点.
结论:
只要类型帮忙, 就动用暗许迭代器和操作符, 例如列表, 字典和文件.
内建项目也定义了迭代器方法. 优先考虑那一个点子, 而不是那多少个再次来到列表的方法.
当然,那样遍历容器时,你将不能修改容器.

Yes:  for key in adict: ...
      if key not in adict: ...
      if obj in alist: ...
      for line in afile: ...
      for k, v in dict.iteritems(): ...

No:   for key in adict.keys(): ...
      if not adict.has_key(key): ...
      for line in afile.readlines(): ...

结论:

采纳 import x 来导入包和模块.

利用 from x import y , 当中x是包前缀, y是不带前缀的模块名.

行使 from x import y as z, 假诺多个要导入的模块都叫做y可能y太长了.

譬如, 模块 sound.effects.echo 能够用如下格局导入:

from sound.effects import echo

echo.EchoFilter(input, output, delay=0.7, atten=4)

导入时不用使用相对名称. 就算模块在同三个包中, 也要利用完整包名.
那能支持你避免无意间导入3个包两遍.

生成器

Tip
按需使用生成器.

定义:
所谓生成器函数, 便是每当它实施1遍变动(yield)语句, 它就重临一个迭代器,
那几个迭代器生成二个值. 生成值后, 生成器函数的运维情况将被挂起,
直到下3次生成.
优点:
简化代码, 因为每一回调用时, 局地变量和控制流的气象都会被保存.
比起2回创设一文山会海值的函数, 生成器使用的内部存款和储蓄器更少.
缺点:
没有.
结论:
鼓励施用. 注意在生成器函数的文档字符串中行使”Yields:”而不是”Returns:”.
(译者注: 参看
注释
)

叁 、使用模块的万事径名来导入每种模块

Lambda函数

Tip
适用于单行函数

定义:
与话语相反, lambda在贰个表明式中定义匿名函数. 常用来为 map()
filter() 之类的高阶函数定义回调函数大概操作符.
优点:
方便.
缺点:
比本地函数更难阅读和调节和测试. 没有函数名代表堆栈跟踪更难精晓.
由于lambda函数平常只含有二个表明式, 由此其表达能力有限.
结论:
适用于单行函数. 要是代码超过60-77个字符, 最好恐怕定义成常规(嵌套)函数.

对于广泛的操作符,例如乘法操作符,使用 operator
模块中的函数以取代lambda函数. 例如, 推荐使用 operator.mul , 而不是
lambda x, y: x * y .

优点:

防止模块名争辩. 查找包更不难.

规范表明式

Tip
适用于单行函数

定义:
规格表明式是对此if语句的一种特别不难的句法规则. 例如:
x = 1 if cond else 2 .
优点:
比if语句尤其简便易行和方便.
缺点:
比if语句难于阅读. 倘若说明式非常长, 难于固定条件.
结论:
适用于单行函数. 在别的意况下,推荐使用完整的if语句.

缺点:

配备代码变难, 因为你不能够不复制包层次.

暗中认可参数值

Tip
适用于多数景况.

定义:
您能够在函数参数列表的末尾钦点变量的值, 例如, def foo(a, b = 0): .
假使调用foo时只带一个参数, 则b被设为0. 万一带五个参数,
则b的值等于第三个参数.
优点:
你平常会蒙受一些采纳大批量暗中认可值的函数,
但偶尔(相比较少见)你想要覆盖这几个暗许值.
暗中认可参数值提供了一种简单的章程来形成那件事,
你不须求为那么些罕见的例外定义大量函数. 同时,
Python也不协助重载方法和函数, 私下认可参数是一种”仿造”重载行为的简短情势.
缺点:
私下认可参数只在模块加载时求值3遍. 要是参数是列表或字典之类的可变类型,
那大概会造成难点. 假如函数修改了目的(例如向列表追加项),
私下认可值就被改动了.
结论:
勉励接纳, 可是有如下注意事项:

不要在函数或方法定义中使用可变对象作为暗中认可值.

Yes: def foo(a, b=None):
         if b is None:
             b = []

No:  def foo(a, b=[]):
         ...
No:  def foo(a, b=time.time()):  # The time the module was loaded???
         ...
No:  def foo(a, b=FLAGS.my_thing):  # sys.argv has not yet been parsed...
         ...

结论:

抱有的新代码都应该用全体包名来导入每一种模块.

相应像上面那样导入:

# Reference in code with complete name.
import sound.effects.echo

# Reference in code with just module name (preferred).
from sound.effects import echo

属性 properties

Tip
做客和设置数据成员时, 你平凡会利用简易, 轻量级的拜访和设置函数.
提出用属性(properties)来顶替它们.

定义:
一种用于包装措施调用的形式. 当运算量相当的小,
它是获取和装置属性(attribute)的科班格局.
优点:
透过免去不难的习性(attribute)访问时显式的get和set方法调用, 可读性升高了.
允许懒惰的总括. 用Pythonic的不二法门来维护类的接口. 就品质而言,
当直接待上访问变量是理所当然的, 添加访问方法就呈现琐碎而无心义.
使用品质(properties)能够绕过那些标题.
现在也足以在不破坏接口的景况下将做客方法加上.
缺点:
属性(properties)是在get和set方法注解后钦命,
那亟需使用者在接下去的代码中注意:
set和get是用来属性(properties)的(除了用 @property
装饰器制造的只读属性). 必须继承自object类.
大概藏身比如操作符重载之类的副效率. 继承时恐怕会令人怀疑.
结论:
您平时习惯于选取访问或安装方法来拜会或设置数据, 它们简单而轻量.
可是我们提出你在新的代码中选择属性. 只读属性应该用 @property 装饰器
来创建.

万一子类没有覆盖属性, 那么属性的继续可能看起来不显著.
因而使用者必须保证走访方法直接被调用,
以保障子类中的重载方法被属性调用(使用模板方法设计方式).

Yes: import math

     class Square(object):
         """A square with two properties: a writable area and a read-only perimeter.

         To use:
         >>> sq = Square(3)
         >>> sq.area
         9
         >>> sq.perimeter
         12
         >>> sq.area = 16
         >>> sq.side
         4
         >>> sq.perimeter
         16
         """

         def __init__(self, side):
             self.side = side

         def __get_area(self):
             """Calculates the 'area' property."""
             return self.side ** 2

         def ___get_area(self):
             """Indirect accessor for 'area' property."""
             return self.__get_area()

         def __set_area(self, area):
             """Sets the 'area' property."""
             self.side = math.sqrt(area)

         def ___set_area(self, area):
             """Indirect setter for 'area' property."""
             self._SetArea(area)

         area = property(___get_area, ___set_area,
                         doc="""Gets or sets the area of the square.""")

         @property
         def perimeter(self):
             return self.side * 4

(译者注: 老实说, 作者觉着那段示例代码很不对劲, 有必不可少如此蛋疼吗?)

④ 、允许行使越发, 但必须小心

True or False的求值

Tip
尽量使用隐式false

定义:
Python在布尔上下文中会将一些值求值为false. 按简单的直觉来讲,
便是拥有的”空”值都被认为是false. 由此0, None, [], {}, “”
都被认为是false.
优点:
选择Python布尔值的规范语句更易读也更不易犯错. 抢先59%动静下, 也更快.
缺点:
对C/C++开发人士来说, 恐怕看起来有些怪.
结论:
尽心尽力采用隐式的false, 例如: 使用 if foo: 而不是 if foo != []: .
不过如故有局地注意事项必要你记住:

  1. 世代不要用==只怕!=来比较单件, 比如None. 使用is只怕is not.

  2. 只顾: 当你写下 if x: 时, 你实际表示的是 if x is not None . 例如:
    当你要测试2个私下认可值是None的变量或参数是不是被设为其余值.
    那么些值在布尔语义下只怕是false!

  3. 世世代代不要用==将一个布尔量与false相相比较. 使用 if not x: 代替.
    要是你供给区分false和None, 你应该用像 if not x and x is not None:
    那样的语句.

  4. 对此连串(字符串, 列表, 元组), 要注意空类别是false. 因而
    if not seq: 或者 if seq:if len(seq):if not len(seq):
    要更好.

  5. 处理整数时, 使用隐式false可能会寸进尺退(即十分大心将None当做0来处理).
    你能够将3个已知是整型(且不是len()的回到结果)的值与0比较.

Yes: if not users:
         print 'no users'

     if foo == 0:
         self.handle_zero()

     if i % 10 == 0:
         self.handle_multiple_of_ten()


No:  if len(users) == 0:
         print 'no users'

     if foo is not None and not foo:
         self.handle_zero()

     if not i % 10:
         self.handle_multiple_of_ten()
  1. 留意‘0’(字符串)会被作为true.

定义:

尤其是一种跳出代码块的常规控制流来处理错误大概其余格外条件的格局.

老式的言语特征

Tip
尽心尽力使用字符串方法取代字符串模块. 使用函数调用语法取代apply().
使用列表推导, for循环取代filter(),map()以及reduce().

定义:
此时此刻版本的Python提供了豪门常见更爱好的代表品.
结论:
作者们不行使不支持这么些特色的Python版本, 所以没理由不用新的格局.

Yes: words = foo.split(':')

     [x[1] for x in my_list if x[2] == 5]

     map(math.sqrt, data)    # Ok. No inlined lambda expression.

     fn(*args, **kwargs)

No:  words = string.split(foo, ':')

     map(lambda x: x[1], filter(lambda x: x[2] == 5, my_list))

     apply(fn, args, kwargs)

优点:

常规操作代码的控制流不会和错误处理代码混在一起. 当某种条件发生时,
它也同意控制流跳过八个框架. 例如, 一步跳出N个嵌套的函数,
而不必继续执行错误的代码.

词法效用域 Lexical Scoping

Tip

引进使用

定义:
嵌套的Python函数能够引用外层函数中定义的变量, 但是不可能对它们赋值.
变量绑定的分析是选拔词法功能域, 也正是基于静态的主次文本.
对三个块中的某些名称的其他赋值都会促成Python将对该名称的整套引用当做局地变量,
甚至是赋值前的处理. 要是境遇global注解, 该名称就会被当作全局变量.

八个使用那性格格的例子:

def get_adder(summand1):
    """Returns a function that adds numbers to a given number."""
    def adder(summand2):
        return summand1 + summand2

    return adder

(译者注: 这么些事例有点古怪, 你应当这么使用这几个函数:
sum = get_adder(summand1)(summand2) )
优点:
通常能够拉动更为清晰, 优雅的代码.
特别会让有经验的Lisp和Scheme(还有Haskell, ML等)程序员感到欣慰.
缺点:
大概导致令人迷惑的bug. 例如下边那几个遵照
PEP-0227
的例子:

i = 4
def foo(x):
    def bar():
        print i,
    # ...
    # A bunch of code here
    # ...
    for i in x:  # Ah, i *is* local to Foo, so this is what Bar sees
        print i,
    bar()

因此 foo([1, 2, 3]) 会打印 1 2 3 3 , 不是 1 2 3 4 .

(译者注: x是贰个列表,
for循环其实是将x中的值依次赋给i.那样对i的赋值就隐式的发生了,
整个foo函数体中的i都会被当做局地变量, 包含bar()中的那么些.
那或多或少与C++之类的静态语言依旧有相当的大距离的.)
结论:
勉励使用.

缺点:

莫不会造成令人猜疑的操纵流. 调用库时简单失去错误意况.

函数与措施装饰器

Tip
借使好处很明朗, 就明智而严格的运用装饰器

定义:
用以函数及艺术的装饰器
(相当于@标记). 最常见的装饰器是@classmethod 和@staticmethod,
用于将常规函数转换到类方法或静态方法. 但是,
装饰器语法也同意用户自定义装饰器. 尤其地, 对于有些函数 my_decorator ,
上边包车型地铁两段代码是如出一辙的:

class C(object):
   @my_decorator
   def method(self):
       # method body ...
class C(object):
    def method(self):
        # method body ...
    method = my_decorator(method)

优点:
淡雅的在函数上内定一些转换. 该转换大概缩减部分重新代码,
保持已有函数不变(enforce invariants), 等.
缺点:
装饰器能够在函数的参数或重回值上实施其它操作,
那或然造成令人惊叹的隐藏行为. 而且, 装饰器在导入时执行.
从装饰器代码的失败中回复特别不或许.
结论:
一旦好处很鲜明, 就明智而严俊的施用装饰器.
装饰器应该遵循和函数一样的导入和命名规则.
装饰器的python文档应该清楚的求证该函数是二个装饰器.
请为装饰器编写单元测试.

幸免装饰器本人对外场的正视性(即决不借助于文件, socket, 数据库连接等),
因为装饰器运营时这么些能源可能不可用(由 pydoc 或其余工具导入).
应该保障二个用有效参数调用的装饰器在具备境况下都是打响的.

装饰器是一种奇特殊形体式的”超级代码”. 参考后边境海关于 Main 的话题.

结论:

老大必须信守特定条件:

像那样触发至极: raise MyException(“Error message”) 恐怕 raise
MyException . 不要采纳多个参数的花样( raise MyException, “Error message”
)恐怕过时的字符串十分( raise “Error message” ).

模块或包应该定义自身的特定域的不行基类,
那些基类应该从内建的Exception类继承. 模块的不得了基类应该称为”Error”.

class Error(Exception):
    pass

千古不要采用 except: 语句来捕获全体越发, 也绝不捕获 Exception 或者StandardError , 除非你打算重新触发该特别,
或许您早就在现阶段线程的最外层(记得依然要打字与印刷一条错误音讯). 在丰裕那上边,
Python万分宽容, except: 真的会捕获包罗Python语法错误在内的其他错误. 使用
except: 很简单隐藏真正的bug.

尽量收缩try/except块中的代码量. try块的体量越大,
期望之外的非常就越简单被触发. 那种情况下, try/except块将潜伏真正的错误.

行使finally子句来实施这1个无论try块中有没有不行都应该被执行的代码.
那对于清理能源日常很有用, 例如关闭文件.

当捕获非常时, 使用 as 而不用用逗号. 例如

try:
    raise Error
except Error as error:
    pass

线程

Tip
毫无借助内建品种的原子性.

虽说Python的内建项目例如字典看上去拥有原子操作,
但是在好几情况下它们依然不是原子的(即:
如若__hash____eq__被落成为Python方法)且它们的原子性是靠不住的.
你也不能够指望原子变量赋值(因为那些反过来正视字典).

预先选择Queue模块的 Queue 数据类型作为线程间的数据通讯情势. 其它,
使用threading模块及其锁原语(locking primitives).
精晓条件变量的熨帖使用办法, 那样您就足以应用 threading.Condition
来取代低级其他锁了.

⑤ 、避免全局变量

威力过大的特点

Tip
制止使用那个特征

定义:
Python是一种非常灵活的语言, 它为你提供了累累花里胡哨的天性,
诸如元类(metaclasses), 字节码访问, 任意编写翻译(on-the-fly compilation),
动态继承, 对象父类重定义(object reparenting), 导入黑客(import hacks),
反射, 系统内修改(modification of system internals), 等等.
优点:
强劲的语言特征, 能让您的代码更紧密.
缺点:
接纳那么些很”酷”的特征12分诱人, 但不是绝对须要.
使用奇技淫巧的代码将越是难以阅读和调节和测试. 先导容许幸亏(对原我而言),
但当你回想代码, 它们恐怕会比这些稍长一点可是很直白的代码越发不便精通.
结论:
在您的代码中防止那么些性情.

定义:

概念在模块级的变量.

Python风格规范

优点:

有时有用.

分号

Tip
无须在行尾加分号, 也无须用分号将两条命令放在同等行.

缺点:

导入时或然变动模块行为, 因为导入模块时会对模块级变量赋值.

行长度

Tip
每行不当先八十个字符

例外:

  1. 长的导入模块语句
  2. 注脚里的U福睿斯L

毫不使用反斜杠连接行.

Python会将 圆括号,
中括号和花括号中的行隐式的连接起来

, 你能够选拔那些特点. 假使急需, 你能够在表明式外围扩展一对额外的圆括号.

Yes: foo_bar(self, width, height, color='black', design=None, x='foo',
             emphasis=None, highlight=0)

     if (width == 0 and height == 0 and
         color == 'red' and emphasis == 'strong'):

假设2个文本字符串在一行放不下, 能够使用圆括号来促成隐式行连接:

x = ('This will build a very long long '
     'long long long long long long string')

在诠释中,假设须要,将长的U途乐L放在一行上。

Yes:  # See details at
      # http://www.example.com/us/developer/documentation/api/content/v2.0/csv_file_name_extension_full_specification.html

No:  # See details at
     # http://www.example.com/us/developer/documentation/api/content/\
     # v2.0/csv_file_name_extension_full_specification.html

专注下边例子中的成分缩进; 你能够在本文的 缩进 部分找到解释.

结论:

幸免选取全局变量, 用类变量来代替. 但也有局地分化:

剧本的默许选项.
模块级常量. 例如: PI = 3.14159. 常量应该全大写, 用下划线连接.
有时候用全局变量来缓存值只怕当作函数再次回到值很有用.
只要急需, 全局变量应该仅在模块内部可用, 并通过模块级的公家函数来访问.

括号

Tip
宁缺毋滥的利用括号

唯有是用来落举办连接, 不然毫不在回去语句或条件语句中使用括号.
可是在元组两边使用括号是足以的.

Yes: if foo:
         bar()
     while x:
         x = bar()
     if x and y:
         bar()
     if not x:
         bar()
     return foo
     for (x, y) in dict.items(): ...

No:  if (x):
         bar()
     if not(x):
         bar()
     return (foo)

⑥ 、鼓励施用嵌套/本地/内部类或函数

缩进

Tip
用两个空格来缩进代码

纯属不要用tab, 也不要tab和空格混用. 对于行连接的景况,
你应当依旧垂直对齐换行的要素(见 行长度 部分的示范),
可能选拔4空格的悬挂式缩进(那时第3行不应有有参数):

Yes:   # Aligned with opening delimiter
       foo = long_function_name(var_one, var_two,
                                var_three, var_four)

       # Aligned with opening delimiter in a dictionary
       foo = {
           long_dictionary_key: value1 +
                                value2,
           ...
       }

       # 4-space hanging indent; nothing on first line
       foo = long_function_name(
           var_one, var_two, var_three,
           var_four)

       # 4-space hanging indent in a dictionary
       foo = {
           long_dictionary_key:
               long_dictionary_value,
           ...
       }

No:    # Stuff on first line forbidden
      foo = long_function_name(var_one, var_two,
          var_three, var_four)

      # 2-space hanging indent forbidden
      foo = long_function_name(
        var_one, var_two, var_three,
        var_four)

      # No hanging indent in a dictionary
      foo = {
          long_dictionary_key:
              long_dictionary_value,
              ...
      }

定义:

类能够定义在艺术, 函数或许类中. 函数能够定义在形式或函数中.
封闭区间中定义的变量对嵌套函数是只读的.

空行

Tip
一品定义之间空两行, 方法定义之间空一行

头等定义之间空两行, 比如函数大概类定义. 方法定义,
类定义与第3个法子之间, 都应该空一行. 函数或方法中,
某个地方要是你以为极度, 就空一行.

优点:

同意定义仅用于有效限制的工具类和函数.

空格

Tip
根据专业的排版规范来使用标点两边的空格

括号内不要有空格.

Yes: spam(ham[1], {eggs: 2}, [])

No:  spam( ham[ 1 ], { eggs: 2 }, [ ] )

决不在逗号, 分号, 冒号前面加空格, 但应该在它们前面加(除了在行尾).

Yes: if x == 4:
         print x, y
     x, y = y, x

No:  if x == 4 :
         print x , y
     x , y = y , x

参数列表, 索引或切片的左括号前不应加空格.

Yes: spam(1)

no: spam (1)

Yes: dict['key'] = list[index]

No:  dict ['key'] = list [index]

在二元操作符两边都抬高三个空格, 比如赋值(=), 相比(==, <, >, !=,
<>, <=, >=, in, not in, is, is not), 布尔(and, or, not).
至于算术操作符两边的空格该怎么运用, 须要你协调优质判断.
可是两侧务须求维持一致.

Yes: x == 1

No:  x<1

当’=’用于提示关键字参数或私下认可参数值时, 不要在其两侧使用空格.

Yes: def complex(real, imag=0.0): return magic(r=real, i=imag)

No:  def complex(real, imag = 0.0): return magic(r = real, i = imag)

并非用空格来垂直对齐多行间的符号, 因为那会变成保险的负责(适用于:, #,
=等):

Yes:
     foo = 1000  # comment
     long_name = 2  # comment that should not be aligned

     dictionary = {
         "foo": 1,
         "long_name": 2,
         }

No:
     foo       = 1000  # comment
     long_name = 2     # comment that should not be aligned

     dictionary = {
         "foo"      : 1,
         "long_name": 2,
         }

缺点:

嵌套类或局项指标实例无法连串化(pickled).

Python 解析器

Tip
大部分分.py文件不必以#!作为文件的初阶. 依据
PEP-394
, 程序的main文件应该以#!/usr/bin/python2或者 #!/usr/bin/python3开始.

(译者注: 在微型总括机科学中,
Shebang
(也称为Hashbang)是二个由井号和叹号构成的字符串行(#!),
其出现在文件文件的首先行的前多少个字符. 在文书中留存Shebang的动静下,
类Unix操作系统的程序载入器会分析Shebang后的内容,
将这个情节作为解释器指令, 并调用该指令,
并将载有Shebang的公文路径作为该解释器的参数. 例如,
以指令#!/bin/sh先河的公文在执行时会实际调用/bin/sh程序.)
#!先用于扶持内核找到Python解释器, 但是在导入模块时, 将会被忽略.
由此唯有被直接实施的文书中才有必不可少参预#!.

结论:

推荐介绍使用.

注释

Tip
保证对模块, 函数, 方法和行内注释使用科学的作风 文书档案字符串

Python有一种独一无二的的笺注情势: 使用文书档案字符串. 文档字符串是包, 模块,
类或函数里的首先个语句. 那些字符串能够经过对象的doc分子被电动提取,
并且被pydoc所用. (你能够在你的模块上运转pydoc试一把, 看看它长什么).
大家对文书档案字符串的常规是使用三重双引号”“”(
PEP-257
). 多个文书档案字符串应该这么组织: 首先是单排以句号,
问号或咋舌号结尾的概述(可能该文书档案字符串单纯只有一行). 接着是多少个空行.
接着是文书档案字符串剩下的有的, 它应有与文档字符串的首先行的首先个引号对齐.
下边有越来越多文书档案字符串的格式化规范.
模块

种种文件应当包涵叁个许可样板. 依照项目选择的特许(例如, Apache 2.0, BSD,
LGPL, GPL), 选择合适的样板.
函数和章程

下文所指的函数,包罗函数, 方法, 以及生成器.

贰个函数必须求有文书档案字符串, 除非它满意以下标准:

  1. 表面不可知
  2. 那些短小
  3. 不难明了

文书档案字符串应该包涵函数做什么, 以及输入和输出的详细描述. 平日,
不该描述”怎么办”, 除非是某个繁杂的算法. 文书档案字符串应该提供丰裕的信息,
当外人编写代码调用该函数时, 他不须要看一行代码,
只要看文书档案字符串就足以了. 对于复杂的代码,
在代码旁边加注释会比使用文书档案字符串更有意义.

关于函数的多少个地方应当在一定的小节中展开描述记录, 这多少个地方如下文所述.
每节应该以2个标题行初始. 标题行以冒号结尾. 除标题行外,
节的任何情节应被缩进1个空格.

Args:
列出每一种参数的名字, 并在名字后使用贰个冒号和2个空格,
分隔对该参数的描述.假若描述太长当先了单行80字符,使用2或然多少个空格的悬挂缩进(与公事别的部分保持一致).
描述应该包涵所需的连串和含义.
假设一个函数接受foo(可变长度参数列表)大概bar (任意关键字参数),
应该详细列出
foo和**bar.

Returns: (或然 Yields: 用于生成器)
讲述重返值的品类和语义. 假设函数重回None, 这一有些能够省略.

Raises:
列出与接口有关的具有相当.

def fetch_bigtable_rows(big_table, keys, other_silly_variable=None):
    """Fetches rows from a Bigtable.

    Retrieves rows pertaining to the given keys from the Table instance
    represented by big_table.  Silly things may happen if
    other_silly_variable is not None.

    Args:
        big_table: An open Bigtable Table instance.
        keys: A sequence of strings representing the key of each table row
            to fetch.
        other_silly_variable: Another optional variable, that has a much
            longer name than the other args, and which does nothing.

    Returns:
        A dict mapping keys to the corresponding table row data
        fetched. Each row is represented as a tuple of strings. For
        example:

        {'Serak': ('Rigel VII', 'Preparer'),
         'Zim': ('Irk', 'Invader'),
         'Lrrr': ('Omicron Persei 8', 'Emperor')}

        If a key from the keys argument is missing from the dictionary,
        then that row was not found in the table.

    Raises:
        IOError: An error occurred accessing the bigtable.Table object.
    """
    pass

类应该在其定义下有1个用来描述该类的文书档案字符串.
假设你的类有国有性质(Attributes),
那么文书档案中应该有2个属性(Attributes)段.
并且应该遵照和函数参数相同的格式.

class SampleClass(object):
    """Summary of class here.

    Longer class information....
    Longer class information....

    Attributes:
        likes_spam: A boolean indicating if we like SPAM or not.
        eggs: An integer count of the eggs we have laid.
    """

    def __init__(self, likes_spam=False):
        """Inits SampleClass with blah."""
        self.likes_spam = likes_spam
        self.eggs = 0

    def public_method(self):
        """Performs operation blah."""

块注释和行注释

最急需写注释的是代码中那2个技巧性的有的. 假设你在下次
代码审查
的时候必须解释一下, 那么你应该以后就给它写注释. 对于复杂的操作,
应该在其操作起来前写上多少行注释. 对于不是侦破的代码,
应在其行尾添加注释.

# We use a weighted dictionary search to find out where i is in
# the array.  We extrapolate position based on the largest num
# in the array and the array size and then do binary search to
# get the exact number.

if i & (i-1) == 0:        # true iff i is a power of 2

为了增长可读性, 注释应该至少离开代码二个空格.

一面, 毫不要讲述代码. 若是阅读代码的人比你更懂Python,
他只是不精通你的代码要做什么.

# BAD COMMENT: Now go through the b array and make sure whenever i occurs
# the next element is i+1

七 、能够在简要情状下使用列表推导

Tip
只要四个类不接二连三自其余类, 就显式的从object继承. 嵌套类也一样.

Yes: class SampleClass(object):
         pass


     class OuterClass(object):

         class InnerClass(object):
             pass


     class ChildClass(ParentClass):
         """Explicitly inherits from another class already."""

No: class SampleClass:
        pass


    class OuterClass:

        class InnerClass:
            pass

继承自 object 是为了使属性(properties)平时干活,
并且那样能够爱惜你的代码, 使其不受Python
三千的一个独特的私人住房不包容性影响. 那样做也定义了一部分特殊的形式,
那个艺术达成了对象的暗中同意语义, 包涵
__new__, __init__, __delattr__, __getattribute__, __setattr__, __hash__, __repr__, and __str__
.

定义:

列表推导(list comprehensions)与生成器表达式(generator
expression)提供了一种精简高效的措施来成立列表和迭代器, 而不必借助map(),
filter(), 或许lambda.

字符串

Tip
不怕参数都是字符串, 使用%操作符只怕格式化方法格式化字符串.
可是也不可能等量齐观, 你要求在+和%中间能够判定.

Yes: x = a + b
     x = '%s, %s!' % (imperative, expletive)
     x = '{}, {}!'.format(imperative, expletive)
     x = 'name: %s; score: %d' % (name, n)
     x = 'name: {}; score: {}'.format(name, n)

No: x = '%s%s' % (a, b)  # use + in this case
    x = '{}{}'.format(a, b)  # use + in this case
    x = imperative + ', ' + expletive + '!'
    x = 'name: ' + name + '; score: ' + str(n)

幸免在循环中用+和+=操作符来累加字符串. 由于字符串是不可变的,
那样做会成立不须求的权且对象, 并且导致1遍方而不是线性的运维时间.
作为替代方案, 你能够将各样子串参预列表, 然后在循环甘休后用 .join
连接列表. (也能够将每一个子串写入贰个 cStringIO.StringIO 缓存中.)

Yes: items = ['<table>']
     for last_name, first_name in employee_list:
         items.append('<tr><td>%s, %s</td></tr>' % (last_name, first_name))
     items.append('</table>')
     employee_table = ''.join(items)

No: employee_table = '<table>'
    for last_name, first_name in employee_list:
        employee_table += '<tr><td>%s, %s</td></tr>' % (last_name, first_name)
    employee_table += '</table>'

在同一个文本中, 保持利用字符串引号的一模一样性.
使用单引号’大概双引号”之一用以引用字符串, 并在平等文件中沿用.
在字符串内足以选拔别的一种引号, 以幸免在字符串中应用.
GPyLint已经参与了这一检查.

(译者注:GPyLint疑为笔误, 应为PyLint.)

Yes:
     Python('Why are you hiding your eyes?')
     Gollum("I'm scared of lint errors.")
     Narrator('"Good!" thought a happy Python reviewer.')

No:
     Python("Why are you hiding your eyes?")
     Gollum('The lint. It burns. It burns us.')
     Gollum("Always the great lint. Watching. Watching.")

为多行字符串使用三重双引号”“”而非三重单引号’‘’.
当且仅当项目中运用单引号’来引用字符串时,
才恐怕会使用三重’‘’为非文书档案字符串的多行字符串来标识引用.
文书档案字符串必须接纳三重双引号”“”. 可是要小心, 经常用隐式行连接更清楚,
因为多行字符串与程序其他一些的缩进形式分化.

Yes:
    print ("This is much nicer.\n"
           "Do it this way.\n")

No:
      print """This is pretty ugly.
  Don't do this.
  """

优点:

总结的列表推导能够比任何的列表创立方法尤其清晰不难.
生成器表明式能够分外飞跃, 因为它们幸免了创制整个列表.

文件和sockets

Tip
在文件和sockets甘休时, 显式的关闭它.

除文件外, sockets或任何类似文件的靶子在没有须要的图景下开辟,
会有许多副成效, 例如:

  1. 它们或然会损耗一定量的系统财富,如文件讲述符.假诺那几个能源在使用后不曾马上归还系统,那么用于拍卖那么些目的的代码会将能源消耗殆尽.
  2. 具有文件将会阻碍对于文本的别样诸如移动、删除之类的操作.
  3. 单纯是从逻辑上关闭文件和sockets,那么它们如故或然会被其共享的主次在无意识中进行读恐怕写操作.只有当它们确实被关门后,对于它们尝试实行读可能写操作将会跑出尤其,并使得难题飞快显现出来.

并且,幻想当文件对象析构时,文件和sockets会自行关闭,试图将文件对象的生命周期和文件的情景绑定在一道的想法,都以不具体的.
因为有如下原因:

  1. 从未其余措施能够确定保障运转条件会真的的履行文书的析构.不一致的Python实现应用差异的内部存储器管理技术,比如延时垃圾处理机制.
    延时垃圾处理机制大概会导致对象生命周期被轻易无界定的延长.
  2. 对此文本意外的引用,会招致对于文本的全体时间大于预想(比如对于尤其的跟踪,
    包括有全局变量等).

推荐介绍使用“with”语句
以管理文件:

with open("hello.txt") as hello_file:
    for line in hello_file:
        print line

对此不支持选择”with”语句的近乎文件的指标,使用 contextlib.closing():

import contextlib

with contextlib.closing(urllib.urlopen("http://www.python.org/")) as front_page:
    for line in front_page:
        print line

Legacy AppEngine 中Python 2.5的代码如应用”with”语句, 须要添加
“from __future__ import with_statement”.

缺点:

复杂的列表推导或许生成器表明式或者难以阅读.

TODO注释

Tip
为一时半刻期码应用TODO注释, 它是一种短期化解方案. 不算圆满, 但够好了.

TODO注释应该在富有初阶处带有”TODO”字符串,
紧跟着是用括号括起来的您的名字, email地址或别的标识符.
然后是二个可选的冒号. 接着必须有一行注释, 解释要做什么样.
主要目标是为着有多个联合的TODO格式,
那样添加注释的人就足以查找到(并能够按需提供更多细节).
写了TODO注释并不保障写的人会亲自化解难点. 当你写了八个TODO,
请注上你的名字.

# TODO(kl@gmail.com): Use a "*" here for string repetition.
# TODO(Zeke) Change this to use relations.

假使您的TODO是”以后做某事”的款型,
那么请保管您包罗了三个点名的日期(“二〇〇九年5月缓解”)恐怕三个一定的风浪(“等到持有的客户都得以拍卖XML请求就移除那么些代码”).

结论:

适用于简单意况. 各类部分应该单独置于一行: 映射表明式, for语句,
过滤器表明式. 禁止多重for语句或过滤器表明式. 复杂气象下大概接纳循环.
Yes:

  result = []
  for x in range(10):
      for y in range(5):
          if x * y > 10:
              result.append((x, y))

  for x in xrange(5):
      for y in xrange(5):
          if x != y:
              for z in xrange(5):
                  if y != z:
                      yield (x, y, z)

  return ((x, complicated_transform(x))
          for x in long_generator_function(parameter)
          if x is not None)

  squares = [x * x for x in range(10)]

  eat(jelly_bean for jelly_bean in jelly_beans
      if jelly_bean.color == 'black')

No:

  result = [(x, y) for x in range(10) for y in range(5) if x * y > 10]

  return ((x, y, z)
          for x in xrange(5)
          for y in xrange(5)
          if x != y
          for z in xrange(5)
          if y != z)

导入格式

Tip
各类导入应该占据一行

Yes: import os
     import sys

No:  import os, sys

导入总应该放在文件顶部, 位于模块注释和文书档案字符串之后,
模块全局变量和常量此前. 导入应该根据从最通用到最不通用的相继分组:

  1. 标准库导入
  2. 其三方库导入
  3. 应用程序钦命导入

每一个分组中, 应该依据每一个模块的完整包路径按字典序排序, 忽略大小写.

import foo
from foo import bar
from foo.bar import baz
from foo.bar import Quux
from Foob import ar

捌 、私下认可迭代器和操作符

语句

Tip
常备每种语句应该占据一行

可是, 假如测试结果与测试语句在一行放得下, 你也足以将它们放在同等行.
假如是if语句, 唯有在并未else时才能这么做. 越发地, 绝不要对 try/except
那样做, 因为try和except无法放在同样行.

Yes:

  if foo: bar(foo)

No:

  if foo: bar(foo)
  else:   baz(foo)

  try:               bar(foo)
  except ValueError: baz(foo)

  try:
      bar(foo)
  except ValueError: baz(foo)

Tip

假设类型援助, 就选取暗中同意迭代器和操作符. 比如列表, 字典及文件等.

访问控制

Tip
在Python中,
对于琐碎又不太主要的拜会函数,你应当一直利用国有变量来取代它们,那样能够制止额外的函数调用耗费.当添加越多效益时,
你能够用属性(property)来保持语法的一律性.

(译者注: 重视封装的面向对象程序员看到那个恐怕会很反感,
因为他俩平昔被感化: 全体成员变量都无法不是私家的! 其实,
那实在是有点麻烦啊.试着去领受Pythonic农学吧)

多只, 借使访问更扑朔迷离, 只怕变量的拜访费用很显然, 那么你应有利用像
get_foo()set_foo() 那样的函数调用.
假若以前的代码行为容许通过质量(property)访问 ,
那么就不要将新的走访函数与性能绑定. 这样,
任何准备通过老方法访问变量的代码就没办法运转,
使用者也就会发觉到复杂产生了变化.

定义:

容器类型, 像字典和列表, 定义了私下认可的迭代器和关系测试操作符(in和not in)

命名

Tip
module_name, package_name, ClassName, method_name,
ExceptionName,function_name, GLOBAL_VAR_NAME, instance_var_name,
function_parameter_name, local_var_name.

应当防止的名号

  1. 单字符名称, 除了计数器和迭代器.
  2. 包/模块名中的连字符(-)
  3. 双下划线起首并最终的名号(Python保留, 例如init)

命名约定

  1. 所谓”内部(Internal)”表示仅模块内可用, 大概, 在类内是保险或个人的.
  2. 用单下划线(_)开端表示模块变量或函数是protected的(使用import *
    from时不会蕴藏).
  3. 用双下划线(__)开端的实例变量或方法表示类内私有.
  4. 将相关的类和甲级函数放在同多少个模块里. 不像Java,
    没须要限制三个类3个模块.
  5. 对类名使用大写字母开始的单词(如CapWords,即Pascal风格),可是模块名应当用小写加下划线的法子(如lower_with_under.py).
    固然已经有成百上千留存的模块使用类似于CapWords.py那样的命名,但现行反革命早已不鼓励那样做,因为假若模块名刚刚和类一致,
    那会令人烦扰.
Type Public Internal
Modules lower_with_under _lower_with_under
Packages lower_with_under
Classes CapWords _CapWords
Exceptions CapWords
Functions lower_with_under() lower_with_under()
Global/Class Constants CAPS_WITH_UNDER CAPS_WITH_UNDER
Global/Class Variables lower_with_under lower_with_under
Instance Variables lower_with_under _lower_with_under (protected) or __lower_with_under (private)
Method Names lower_with_under() _lower_with_under() (protected) or __lower_with_under() (private)
Function/Method Parameters lower_with_under
Local Variables lower_with_under

Python之父吉多推荐的正式

Type Public Internal
Modules lower_with_under _lower_with_under
Packages lower_with_under
Classes CapWords _CapWords
Exceptions CapWords
Functions lower_with_under() lower_with_under()
Global/Class Constants CAPS_WITH_UNDER CAPS_WITH_UNDER
Global/Class Variables lower_with_under lower_with_under
Instance Variables lower_with_under _lower_with_under (protected) or __lower_with_under (private)
Method Names lower_with_under() _lower_with_under() (protected) or __lower_with_under() (private)
Function/Method Parameters lower_with_under
Local Variables lower_with_under

优点:

私下认可操作符和迭代器简单飞速, 它们一直表明了操作, 没有额外的章程调用.
使用暗中同意操作符的函数是通用的. 它能够用于支持该操作的其他类型.

Main

Tip
正是是2个打算被视作脚本的公文,也应有是可导入的.并且简单的导入不应当导致这几个本子的主效能(mainfunctionality)被实施,
那是一种副功用. 主作用应该放在一个main()函数中.

在Python中, pydoc以及单元测试供给模块必须是可导入的.
你的代码应该在执行主程序前总是检查 if __name__ == '__main__' ,
那样当模块被导入时主程序就不会被执行.

def main():
      ...

if __name__ == '__main__':
    main()

负有的五星级代码在模块导入时都会被执行. 要小心不要去调用函数,
创制对象只怕进行那多少个不应该在应用pydoc时实施的操作.

缺点:

你没办法通过阅读形式名来分别对象的项目(例如, has_key()意味着字典).
然而这也是优点.
结论:
假如类型协理, 就使用私下认可迭代器和操作符, 例如列表, 字典和文件.
内建项目也定义了迭代器方法. 优先考虑这一个点子, 而不是那个再次回到列表的方法.
当然,那样遍历容器时,你将不可能修改容器.

Yes:  for key in adict: ...
      if key not in adict: ...
      if obj in alist: ...
      for line in afile: ...
      for k, v in dict.iteritems(): ...
No:   for key in adict.keys(): ...
      if not adict.has_key(key): ...
      for line in afile.readlines(): ...

临别赠言

请务必保持代码的一致性

倘使你正在编纂代码,
花几分钟看一下周边代码,然后决定风格.如若它们在颇具的算术操作符两边都采纳空格,那么您也理应那样做.
如若它们的注释都用标记包围起来, 那么您的诠释也要那样.

制定风格指南的意在让代码有规可循,那样人们就可以小心于”你在说怎样”,而不是”你在怎么说”.大家在此间给出的是全局的正经,
不过地面包车型地铁正经同样首要.若是您加到多个文书里的代码和原有代码相形见绌,它会让读者心慌意乱.幸免那种景况.

⑨ 、按需使用生成器

参考:

定义:

所谓生成器函数, 就是每当它执行3遍变动(yield)语句, 它就赶回一个迭代器,
这些迭代器生成三个值. 生成值后, 生成器函数的运作情状将被挂起,
直到下一遍生成.

优点:

简化代码, 因为老是调用时, 局地变量和控制流的处境都会被保存.
比起二回创立一密密麻麻值的函数, 生成器使用的内部存款和储蓄器更少.

缺点:

没有.

结论:

勉励选用. 注意在生成器函数的文档字符串中应用”Yields:”而不是”Returns:”.

10、Lambda函数

Tip

适用于单行函数

定义:

与话语相反, lambda在一个表达式中定义匿名函数. 常用于为 map() 和 filter()
之类的高阶函数定义回调函数或然操作符.

优点:

方便.

缺点:

比当地函数更难阅读和调节和测试. 没有函数名代表堆栈跟踪更难精通.
由于lambda函数经常只包涵1个表明式, 因而其表明能力有限.

结论:

适用于单行函数. 假使代码当先60-七十九个字符, 最好仍然定义成常规(嵌套)函数.

对此周边的操作符,例如乘法操作符,使用 operator
模块中的函数以代替lambda函数. 例如, 推荐应用 operator.mul , 而不是
lambda x, y: x * y .

1壹 、条件表明式

Tip

适用于单行函数

定义:

规格表明式是对此if语句的一种尤其容易的句法规则. 例如:

x = 1 if cond else 2 .

优点:

比if语句尤其简便易行和方便.

缺点:

比if语句难于阅读. 假使表明式十分长, 难于固定条件.

结论:

适用于单行函数. 在别的意况下,推荐使用完整的if语句.

1② 、暗中认可参数值

Tip

适用于抢先四分之二情状.

定义:

你能够在函数参数列表的末段钦点变量的值, 例如:

def foo(a, b = 0)

假使调用foo时只带3个参数, 则b被设为0. 比方带多个参数,
则b的值等于第叁个参数.

优点:

您时常会境遇一些运用多量暗中认可值的函数,
但偶尔(比较少见)你想要覆盖这几个暗许值.
暗中同意参数值提供了一种简易的方法来达成这件事,
你不供给为那一个难得的不等定义多量函数. 同时,
Python也不帮忙重载方法和函数, 暗中认可参数是一种”仿造”重载行为的简单格局.

缺点:

暗许参数只在模块加载时求值三遍. 如若参数是列表或字典之类的可变类型,
这说不定会招致难点. 假设函数修改了对象(例如向列表追加项),
默许值就被改动了.

结论:

勉励选用, 可是有如下注意事项:

不用在函数或方法定义中应用可变对象作为默许值.

Yes:

def foo(a, b=None):
         if b is None:
             b = []

No:

def foo(a, b=[]):
         ...

No:

 def foo(a, b=time.time()):  # The time the module was loaded???

No:

def foo(a, b=FLAGS.my_thing):  # sys.argv has not yet been parsed...
         ...

13、属性(properties)

Tip

走访和装置数据成员时, 你平常会采用简便, 轻量级的走访和设置函数.
建议用属性(properties)来代替它们.

定义:

一种用于包装格局调用的格局. 当运算量一点都不大,
它是获取和设置属性(attribute)的正儿八经格局.

优点:

通过解除不难的习性(attribute)访问时显式的get和set方法调用, 可读性升高了.
允许懒惰的总计. 用Pythonic的主意来维护类的接口. 就质量而言,
当直接待上访问变量是创立的, 添加访问方法就展现琐碎而无心义.
使用品质(properties)能够绕过那么些标题.
今后也得以在不破坏接口的意况下将做客方法加上.

缺点:

质量(properties)是在get和set方法阐明后钦定,
那必要使用者在接下去的代码中注意:
set和get是用来属性(properties)的(除了用 @property 装饰器创造的只读属性).
必须继续自object类. 大概暗藏比如操作符重载之类的副作用.
继承时可能会令人狐疑.

结论:

您不足为奇习惯于采纳访问或设置格局来做客或安装数据, 它们不难而轻量.
但是我们提出您在新的代码中利用属性. 只读属性应该用 @property 装饰器
来创造.

若是子类没有覆盖属性, 那么属性的三番五次恐怕看起来不鲜明.
由此使用者必须保险走访方法直接被调用,
以保险子类中的重载方法被属性调用(使用模板方法设计情势).

Yes:

 import math

     class Square(object):
         """A square with two properties: a writable area and a read-only perimeter.

         To use:
         >>> sq = Square(3)
         >>> sq.area
         9
         >>> sq.perimeter
         12
         >>> sq.area = 16
         >>> sq.side
         4
         >>> sq.perimeter
         16
         """

         def __init__(self, side):
             self.side = side

         def __get_area(self):
             """Calculates the 'area' property."""
             return self.side ** 2

         def ___get_area(self):
             """Indirect accessor for 'area' property."""
             return self.__get_area()

         def __set_area(self, area):
             """Sets the 'area' property."""
             self.side = math.sqrt(area)

         def ___set_area(self, area):
             """Indirect setter for 'area' property."""
             self._SetArea(area)

         area = property(___get_area, ___set_area,
                         doc="""Gets or sets the area of the square.""")

         @property
         def perimeter(self):
             return self.side * 4

1四 、尽只怕选用隐式false

定义:

Python在布尔上下文中会将某个值求值为false. 按不难的直觉来讲,
正是全部的”空”值都被认为是false. 由此0, None, [], {}, “”
都被认为是false.

优点:

选拔Python布尔值的尺度语句更易读也更科学犯错. 大多数境况下, 也更快.

缺点:

对C/C++开发职员来说, 恐怕看起来有个别怪.

结论:

尽量使用隐式的false, 例如: 使用 if foo: 而不是 if foo != []: .
可是还是有一部分注意事项供给您难忘:

千古不要用==或然!=来相比较单件, 比如None. 使用is可能is not.

留意: 当你写下 if x: 时, 你实在表示的是 if x is not None . 例如:
当你要测试一个私下认可值是None的变量或参数是还是不是被设为别的值.
那么些值在布尔语义下或然是false!

世代不要用==将2个布尔量与false相相比较. 使用 if not x: 代替.
即便您须求区分false和None, 你应该用像 if not x and x is not None:
那样的语句.

对于体系(字符串, 列表, 元组), 要专注空种类是false. 因而 if not seq: 恐怕if seq: 比 if len(seq): 或 if not len(seq): 要更好.

拍卖整数时, 使用隐式false大概会贪小失大(即相当大心将None当做0来处理).
你能够将1个已知是整型(且不是len()的回来结果)的值与0相比较.

Yes:

if not users:
         print 'no users'

if foo == 0:
         self.handle_zero()

if i % 10 == 0:
         self.handle_multiple_of_ten()

No:

if len(users) == 0:
         print 'no users'

if foo is not None and not foo:
         self.handle_zero()

 if not i % 10:
         self.handle_multiple_of_ten()

留意‘0’(字符串)会被作为true.

1⑤ 、过时的语言特征

Tip

尽量选用字符串方法取代字符串模块. 使用函数调用语法取代apply().
使用列表推导, for循环取代filter(), map()以及reduce().

定义:

现阶段版本的Python提供了豪门常见更欣赏的替代品.

结论:

咱俩不使用不帮助那一个特征的Python版本, 所以没理由不用新的格局.

Yes:

words = foo.split(':')

[x[1] for x in my_list if x[2] == 5]

map(math.sqrt, data)    # Ok. No inlined lambda expression.

fn(*args, **kwargs)

No:

words = string.split(foo, ':')

map(lambda x: x[1], filter(lambda x: x[2] == 5, my_list))

apply(fn, args, kwargs)

1六 、推荐使用词法效能域(Lexical Scoping)

定义:

嵌套的Python函数可以引用外层函数中定义的变量, 不过不能对它们赋值.
变量绑定的解析是运用词法成效域, 也正是依据静态的次序文本.
对二个块中的某些名称的其它赋值都会促成Python将对该名称的全套引用当做局地变量,
甚至是赋值前的处理. 借使赶上global表明, 该名称就会被当做全局变量.

一个运用那个特点的例证:

def get_adder(summand1):
    """Returns a function that adds numbers to a given number."""
    def adder(summand2):
        return summand1 + summand2

    return adder

优点:

平日能够带动更为清晰, 优雅的代码.
特别会让有经历的Lisp和Scheme(还有Haskell, ML等)程序员感到欣慰.

缺点:

恐怕引致令人迷惑的bug. 例如上边这些根据 PEP-0227 的事例:

i = 4
def foo(x):
    def bar():
        print i,
    # ...
    # A bunch of code here
    # ...
    for i in x:  # Ah, i *is* local to Foo, so this is what Bar sees
        print i,
    bar()

因此 foo([1, 2, 3]) 会打印 1 2 3 3 , 不是 1 2 3 4 .

(译者注: x是2个列表,
for循环其实是将x中的值依次赋给i.那样对i的赋值就隐式的产生了,
整个foo函数体中的i都会被看作局地变量, 包蕴bar()中的那多少个.
那或多或少与C++之类的静态语言照旧有相当大差其余.)

结论:

鞭策使用.

1⑦ 、函数与措施装饰器

Tip

假使好处很明朗, 就明智而谨慎的行使装饰器

定义:

用以函数及情势的点缀器 (也正是@标记). 最常见的装饰器是@classmethod
和@staticmethod, 用于将常规函数转换到类方法或静态方法. 可是,
装饰器语法也允许用户自定义装饰器. 尤其地, 对于某些函数 my_decorator ,
上面包车型客车两段代码是均等的:

class C(object):
   @my_decorator
   def method(self):
       # method body ...
class C(object):
    def method(self):
        # method body ...
    method = my_decorator(method)

优点:

优雅的在函数上点名一些转换. 该转换大概回落一些重新代码,
保持已有函数不变(enforce invariants), 等.

缺点:

装饰器能够在函数的参数或重回值上推行别的操作,
那可能导致令人惊奇的隐藏行为. 而且, 装饰器在导入时执行.
从装饰器代码的退步中平复特别不可能.

结论:

一经好处很明显, 就明智而严格的运用装饰器.
装饰器应该服从和函数一样的导入和命名规则.
装饰器的python文档应该清楚的认证该函数是多少个装修器.
请为装饰器编写单元测试.

幸免装饰器本人对外场的依靠(即不用借助于文件, socket, 数据库连接等),
因为装饰器运营时那一个能源或许不可用(由 pydoc 或其余工具导入).
应该保障一个用卓有作用参数调用的装饰器在享有情状下都以马到功成的.

装饰器是一种新鲜方式的”拔尖代码”. 参考前面关于 Main 的话题.

18、线程

Tip

无须借助内建品种的原子性.
虽说Python的内建项目例如字典看上去拥有原子操作,
可是在好几情况下它们照旧不是原子的(即:
如若hasheq被完毕为Python方法)且它们的原子性是靠不住的.
你也不能够指望原子变量赋值(因为那几个反过来重视字典).

先行选取Queue模块的 Queue 数据类型作为线程间的数码通信方式. 别的,
使用threading模块及其锁原语(locking primitives).
了然条件变量的适宜使用格局, 那样你就能够运用 threading.Condition
来代表低级其余锁了.

1九 、制止使用威力过大的天性

定义:

Python是一种至极灵活的语言, 它为你提供了很多花里胡哨的特点,
诸如元类(metaclasses), 字节码访问, 任意编写翻译(on-the-fly compilation),
动态继承, 对象父类重定义(object reparenting), 导入黑客(import hacks),
反射, 系统内修改(modification of system internals), 等等.

优点:

强劲的言语特色, 能让您的代码更紧密.

缺点:

选用那些很”酷”的特征十二分诱人, 但不是纯属需要.
使用奇技淫巧的代码将进一步难以阅读和调节和测试. 起头容许辛亏(对原我而言),
但当您想起代码, 它们大概会比那个稍长一点只是很直接的代码特别难以掌握.

结论:

在您的代码中防止那么些本性.