for x in array:
if x < pivot:
less.append(x)
else:
greater.append(x)Python Language Introduction
Python 1 是由 Guido van Rossum 2 于 1991 年创造的一种广泛使用的解释型、高级编程、通用型编程语言。
Python 的设计哲学强调代码的可读性和简洁的语法,尤其是使用空格缩进划分代码块,而非使用大括号或者关键词。相比于 C++ 或 Java,Python 让开发者能够用更少的代码表达想法。不管是小型还是大型程序,该语言都试图让程序的结构清晰明了。
Python 拥有动态类型系统和垃圾回收功能,能够自动管理内存使用,并且支持多种编程范式,包括面向对象、命令式、函数式和过程式编程。其本身拥有一个巨大而广泛的标准库。

Python 使用缩进 (Tab 或空格) 来组织代码,而不是类似其他语言 (C/C++,Java, R) 使用大括号。使用 Tab 或空格进行缩进没有要求,但应该在一个工程中保持一致。
Python 语句并不以分号 ; 结尾,但分号可以用于一行内多条语句之间的分隔:
所有写在 # 后面的文本将被视为注释并被 Python 解释器忽略:
| 操作符 | 描述 | 操作符 | 描述 |
|---|---|---|---|
a + b |
a 加 b | a - b |
a 减 b |
a * b |
a 乘 b | a / b |
a 除以 b |
a // b |
a 整除以 b | a ** b |
a 的 b 次方 |
a & b |
a 与 b | a丨b |
a 或 b |
a and b |
a 与 b | a or b |
a 或 b |
a ^ b |
a 异或 b | a == b |
a 等于 b |
a != b |
a 不等于 b | a < b, a <= b |
a 小于(等于) b |
a > b, a >= b |
a 大于(等于) b | a is b |
a 和 b 是同一对象 |
a is not b |
a 和 b 不是同一对象 |
Python 中可以通过 if,elif 和 else 控制条件语句,同时在条件中可以使用链式比较:
Python 中可以通过 for 和 while 控制循环语句:
pass 在 Python 中表示“什么也不做”:
range 返回一个迭代器:
Python 通过 def 定义函数:
函数的参数设置灵活多变,例如:
在调用时,如果不指定参数名称,则通过位置判断对应的参数值,例如:
Python 标准库中包含了一个内建类型集合,其中“单值”类型也称为标量类型,6 种标量类型如下表所示:
| 类型 | 描述 |
|---|---|
int |
任意精度无符号整数类型 |
float |
双精度 64 位浮点数值类型 |
bool |
布尔值类型,True 或 False |
None |
Python 的 NULL 值 (仅存在一个实例) |
str |
字符串类型,包含 Unicode (UTF-8 编码) 字符串 |
bytes |
原生 ASCII 字节 (或 Unicode 编码字节) |
反斜杠 \ 为 Python 字符串的转义符号:
当包含大量转义字符时,为了避免书写麻烦,可以在字符串前加一个前缀符号 r 用于表名后续字符为原生字符:
字符串的格式化方法有多种,字符串对象具有使用 % 运算符的内置操作:
通过插入变量名称进行引用:
'Hello, Leo. You are 30.'
使用 ** 直接对字典进行拆包:
使用 append 方法可以将元素添加到尾部:
使用 insert 方法可以将元素插入到指定位置:
调用 sort 方法对列表进行排序(无需新建对象):
通过参数 key 可以指定用于生成排序值的函数:
zip 可以将列表、元组或其他序列的元素配对,新建一个元组构成的列表:
[(1, 'a'), (2, 'b'), (3, 'c')]
zip 可以处理任意长度的序列,它生成列表的长度由最短的序列决定。
字典 dict 是 Python 内建的哈希表类型的数据结构,是一种拥有有灵活存储的键值对集合。在 Python 中使用大括号 {} 可以创建字典,并用逗号将键值对分割,其中键和值均为 Python 对象。
类似访问列表和元组中的元素一样,可以访问、插入或设置字典中的元素:
可以使用 del 或 pop 删除字典的值,pop 方法会在删除的同时返回被删除的值:
可以使用 update 函数将两个词典合并:
也可以用 ** 将两个词典合并:
字典的值可以是任何 Python 对象,但必须为不可变对象,例如:标量,元组等。一个对象是否能够作为键值可以通过 hash 函数来检测一个对象是否可以哈希化。
| 函数 | 替代方法 | 描述 | 函数 | 替代方法 | 描述 |
|---|---|---|---|---|---|
a.add(x) |
N/A | 添加元素 x |
a.clear() |
N/A | 清空所有元素 |
a.remove(x) |
N/A | 移除元素 x |
a.pop() |
N/A | 移除任意位置元素 |
a.union(b) |
a 丨 b |
a 和 b 的并集 |
a.update(b) |
a 丨= b |
将 a 置为 a 和 b 的并集 |
a.intersection(b) |
a & b |
a 和 b 的交集 |
a.intersection_update(b) |
a &= b |
将 a 置为 a 和 b 的交集 |
a.difference(b) |
a - b |
a 和 b 的差集 |
a.difference_update(b) |
a -= b |
将 a 置为 a 和 b 的差集 |
a.issubset(b) |
N/A | a 是否为 b 的子集 |
a.issuperset(b) |
N/A | a 是否为 b 的超集 |
a.isdisjoint(b) |
N/A | a 和 b 是否无交集 |
a.symmetric_difference(b) |
a ^ b |
a 和 b 的对称差集 |
a.symmetric_difference_update(b) |
a ^= b |
将 a 置为 a 和 b 的对称差集 |
列表推导允许过滤一个容器的元素,其用一个简明的表达式转换传递给过滤器的元素,从而生成一个新的列表。列表推导式的基础形式为:
这与下面的 for 循环是等价的:
过滤条件是可以省略的。
不要在行尾加分号, 也不要用分号将两条命令放在同一行。
每行不超过 80 个字符。
Python 会将圆括号, 中括号和花括号中的行隐式的连接起来,可以利用这个特点在表达式外围增加一对额外的圆括号。
在注释中,如果必要,将长的 URL 放在一行上。
# http://www.example.com/us/developer/documentation/api/content/v2.0/do_something.html
# http://www.example.com/us/developer/documentation/api/content/\
# v2.0/do_something.html
宁缺毋滥的使用括号。
除非是用于实现行连接,否则不要在返回语句或条件语句中使用括号。 不过在元组两边使用括号是可以的。
用 4 个空格来缩进代码。
绝对不要用 tab,也不要 tab 和空格混用。对于行连接的情况,你应该要么垂直对齐换行的元素,或者使用 4 空格的悬挂式缩进(第一行不应该有参数)。
在二元操作符两边都加上一个空格,比如赋值 =,比较 ==,<,>,!=,<>,<=,>=,in,not in,is,is not,布尔 and,or,not。 至于算术操作符两边的空格该如何使用,需要你自己好好判断,不过两侧务必要保持一致。
x == 1
x<1
当 = 用于指示关键字参数或默认参数值时,不要在其两侧使用空格。
不要用空格来垂直对齐多行间的标记,因为这会成为维护的负担(适用于 :,#,= 等)。
大部分 .py 文件不必以 #! 开始。根据 PEP-394 ,程序的 main 文件应该以 #!/usr/bin/python2 或者 #!/usr/bin/python3 开始。
在计算机科学中,Shebang(也称为 Hashbang)是一个由井号和叹号构成的字符串行 #!,其出现在文本文件的第一行的前两个字符。在文件中存在 Shebang 的情况下,类 Unix 操作系统的程序载入器会分析 Shebang 后的内容,将这些内容作为解释器指令,并调用该指令,并将载有 Shebang 的文件路径作为该解释器的参数。例如,以指令 #!/bin/sh 开头的文件在执行时会实际调用 /bin/sh 程序。
确保对模块,函数,方法和行内注释使用正确的风格。
Python 有一种独一无二的的注释方式:使用文档字符串。文档字符串是包,模块,类或函数里的第一个语句。这些字符串可以通过对象的 __doc__ 成员被自动提取,并且被 pydoc 所用。我们对文档字符串的惯例是使用三重双引号 """ (PEP-257)。一个文档字符串应该这样组织:首先是一行以句号,问号或惊叹号结尾的概述(或者该文档字符串单纯只有一行)。接着是一个空行。接着是文档字符串剩下的部分,它应该与文档字符串的第一行的第一个引号对齐。下面有更多文档字符串的格式化规范。
每个文件应该包含一个许可样板。根据项目使用的许可(例如,Apache 2.0,BSD,LGPL,GPL),选择合适的样板。
下文所指的函数,包括函数,方法,以及生成器。一个函数必须要有文档字符串,除非它满足以下条件:1. 外部不可见,2. 非常短小,3. 简单明了。
文档字符串应该包含函数做什么,以及输入和输出的详细描述。通常,不应该描述“怎么做”,除非是一些复杂的算法。文档字符串应该提供足够的信息,当别人编写代码调用该函数时,他不需要看一行代码,只要看文档字符串就可以了。对于复杂的代码,在代码旁边加注释会比使用文档字符串更有意义。关于函数的几个方面应该在特定的小节中进行描述记录, 这几个方面如下文所述。每节应该以一个标题行开始。标题行以冒号结尾。除标题行外,节的其他内容应被缩进 2 个空格。
Args:列出每个参数的名字,并在名字后使用一个冒号和一个空格,分隔对该参数的描述。如果描述太长超过了单行 80 字符,使用 2 或者 4 个空格的悬挂缩进(与文件其他部分保持一致)。描述应该包括所需的类型和含义。如果一个函数接受 *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最需要写注释的是代码中那些技巧性的部分。 如果你在下次 代码审查 的时候必须解释一下,那么你应该现在就给它写注释。 对于复杂的操作,应该在其操作开始前写上若干行注释。 对于不是一目了然的代码,应在其行尾添加注释。
为了提高可读性,注释应该至少离开代码 2 个空格。另一方面,绝不要描述代码. 假设阅读代码的人比你更懂 Python,他只是不知道你的代码要做什么。
即使参数都是字符串,使用 % 或者格式化方法格式化字符串。不过也不能一概而论,你需要在 + 和 % 之间好好判定。
避免在循环中用 + 和 += 操作符来累加字符串。由于字符串是不可变的,这样做会创建不必要的临时对象,并且导致二次方而不是线性的运行时间。作为替代方案,你可以将每个子串加入列表,然后在循环结束后用 .join 连接列表。
在同一个文件中,保持使用字符串引号的一致性。使用单引号 ' 或者双引号 " 之一用以引用字符串,并在同一文件中沿用。在字符串内可以使用另外一种引号,以避免在字符串中使用。PyLint 已经加入了这一检查。
为多行字符串使用三重双引号 """ 而非三重单引号 '''。当且仅当项目中使用单引号 ' 来引用字符串时,才可能会使用三重 ''' 为非文档字符串的多行字符串来标识引用。 文档字符串必须使用三重双引号 """。不过要注意,通常用隐式行连接更清晰,因为多行字符串与程序其他部分的缩进方式不一致。
为临时代码使用 TODO 注释,它是一种短期解决方案,不算完美,但够好了。
TODO 注释应该在所有开头处包含 TODO 字符串,紧跟着是用括号括起来的你的名字,email 地址或其它标识符。然后是一个可选的冒号。接着必须有一行注释,解释要做什么。 主要目的是为了有一个统一的 TODO 格式,这样添加注释的人就可以搜索到(并可以按需提供更多细节)。写了 TODO 注释并不保证写的人会亲自解决问题。当你写了一个 TODO,请注上你的名字。
如果你的 TODO 是“将来做某事”的形式,那么请确保你包含了一个指定的日期(“2009 年 11 月解决”)或者一个特定的事件(“等到所有的客户都可以处理XML请求就移除这些代码”)。
每个导入应该独占一行。
导入总应该放在文件顶部,位于模块注释和文档字符串之后,模块全局变量和常量之前。 导入应该按照从最通用到最不通用的顺序分组:1. 标准库导入,2. 第三方库导入,3. 应用程序指定导入。
每种分组中,应该根据每个模块的完整包路径按字典序排序,忽略大小写。
通常每个语句应该独占一行。
不过,如果测试结果与测试语句在一行放得下,你也可以将它们放在同一行。如果是 if 语句,只有在没有 else 时才能这样做。特别地,绝不要对 try/except 这样做,因为 try 和 except 不能放在同一行。
在 Python 中,对于琐碎又不太重要的访问函数,你应该直接使用公有变量来取代它们,这样可以避免额外的函数调用开销。当添加更多功能时,你可以用属性(property)来保持语法的一致性。
重视封装的面向对象程序员看到这个可能会很反感,因为他们一直被教育:所有成员变量都必须是私有的!其实,那真的是有点麻烦啊,试着去接受 Pythonic 哲学吧。
另一方面,如果访问更复杂,或者变量的访问开销很显著,那么你应该使用像 get_foo() 和 set_foo() 这样的函数调用。如果之前的代码行为允许通过属性(property)访问,那么就不要将新的访问函数与属性绑定。这样,任何试图通过老方法访问变量的代码就没法运行,使用者也就会意识到复杂性发生了变化。
module_name, package_name, ClassName, method_name, ExceptionName, function_name, GLOBAL_VAR_NAME, instance_var_name, function_parameter_name, local_var_name
-。__init__)。_ 开头表示模块变量或函数是 protected 的(使用 from module import * 时不会包含)。__ 开头的实例变量或方法表示类内私有。lower_with_under.py)。| 类型 | 公共 | 内部 |
|---|---|---|
| 模块 | lower_with_under |
_lower_with_under |
| 包 | lower_with_under |
|
| 类 | CapWords |
_CapWords |
| 异常 | CapWords |
|
| 函数 | lower_with_under() |
_lower_with_under() |
| 全局/类常量 | CAPS_WITH_UNDER |
_CAPS_WITH_UNDER |
| 全局/类变量 | lower_with_under |
_lower_with_under |
| 实例变量 | lower_with_under |
_lower_with_under(保护) __lower_with_under(私有) |
| 方法名称 | lower_with_under() |
_lower_with_under()(保护) __lower_with_under()(私有) |
| 函数/方法参数/局部变量 | lower_with_under |
即使是一个打算被用作脚本的文件,也应该是可导入的。并且简单的导入不应该导致这个脚本的主功能被执行,这是一种副作用,主功能应该放在一个 main() 函数中。
在 Python 中,pydoc 以及单元测试要求模块必须是可导入的。你的代码应该在执行主程序前总是检查 if __name__ == '__main__' ,这样当模块被导入时主程序就不会被执行。
所有的顶级代码在模块导入时都会被执行。要小心不要去调用函数,创建对象,或者执行那些不应该在使用 pydoc 时执行的操作。
版权所有 © 范叶亮 Leo Van