geekdoc-python-zh/docs/tiny-py-es6-nb
wizardforcel 611491aec1 2024-11-06 12:01:47 2024-11-06 12:01:49 +08:00
..
img 2024-11-06 12:01:47 2024-11-06 12:01:49 +08:00
README.md 2024-11-06 12:01:47 2024-11-06 12:01:49 +08:00
SUMMARY.md 2024-11-06 12:01:47 2024-11-06 12:01:49 +08:00
tiny-py-es6-nb_1.md 2024-11-06 12:01:47 2024-11-06 12:01:49 +08:00
tiny-py-es6-nb_2.md 2024-11-06 12:01:47 2024-11-06 12:01:49 +08:00

README.md

Tiny Python 2.7 笔记

来自:mattharrison/Tiny-Python-2.7-Notebook

介绍

这不是一本教程手册,而是 Python 语法的笔记、表格和示例。它是作者在培训期间创建的额外资源,旨在作为一本实体笔记本进行分发。参与者(偏爱纸质书籍特性的人)可以添加自己的笔记、思考,并获得一本有价值的精选示例参考资料。

运行 Python

安装

要检查 Python 是否已安装,请从终端运行以下命令:

python --version

否则,请从网站安装 Python [1]

[1] python.org

调用 Python

Python 可执行文件的行为会根据你给出的命令行选项而有所不同:

  • 启动 Python REPL

    python
    
    
  • 执行 file.py 文件:

    python file.py
    
    
  • 执行 file.py 文件,并进入 file.py 的 REPL 命名空间:

    python -i file.py
    
    
  • 执行 json/tool.py 模块:

    python -m json.tool
    
    
  • 执行 "print 'hi'"

    python -c "print 'hi'"
    
    

REPL

  • 使用 help 函数阅读模块/类/函数的文档。作为独立的调用,你将进入帮助系统,并可以探索各种主题。

  • 使用 dir 函数列出命名空间的内容,或者如果传入了对象,则列出对象的属性

注意

本书中的大部分代码都是以在 REPL 中执行的方式编写的。如果你正在输入它,请忽略主要和次要提示符(>>>...)。

Python 之禅

在解释器中运行以下内容,你将得到一个彩蛋,描述了 Python 背后的一些精神。这也被编码到了 PEP 20 中:

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the
rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation
to guess.
There should be one --and preferably only one--
obvious way to do it.
Although that way may not be obvious at first
unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a
bad idea.
If the implementation is easy to explain, it may
be a good idea.
Namespaces are one honking great idea -- let's
do more of those!

这些可能只是看起来像是愚蠢的一行代码但其中包含了很多智慧。Python 程序员偶尔回顾一下这些内容,并看看这些内容是否适用于他们的代码是很好的。(或者用来证明他们的代码审查)

内置类型

变量

Python 变量就像牛标签一样,它们指向对象(可以是类、实例、模块或函数),但变量本身不是对象。你可以为不同类型的对象重复使用变量名(尽管你可能不应该这样做):

>>> a = 400     # a points to an integer
>>> a = '400'   # a now points to a string

注意

# 字符表示注释的开始。虽然没有多行注释,但大多数带有 Python 支持的编辑器都可以注释掉一个区域。

../Images/rebind2.png

重用相同变量的示例

数字

Python 包括三种类型的数字字面量:整数浮点数复数

数字类型

类型 示例
整数 14
整数(十六进制) 0xe
整数(八进制) 0o16
整数(二进制) 0b1110
浮点数 14.0
浮点数 1.4e1
复数 14+0j

有许多用于操作数字的内置函数,如 absminmaxceil。还可以查看标准库中的 mathrandom 模块。

数字魔术方法

操作 提供者 结果
abs(num) __abs__ num 的绝对值
num + num2 __add__ 加法
bool(num) __bool__ 布尔强制转换
num / num2 __div__ 除法
num == num2 __eq__ 相等性
float(num) __float__ 浮点数强制转换
num // num2 __floordiv__ 整数除法
num >= num2 __ge__ 大于或等于
num > num2 __gt__ 大于
int(num) __int__ 整数强制转换
long(num) __long__ 长整数强制转换
num <= num2 __le__ 小于或等于
num < num2 __lt__ 小于
num % num2 __mod__ 取模
num * num2 __mul__ 乘法
num != num2 __ne__ 不相等
-num __neg__ 负数
+num __pos__ 正数
num ** num2 __pow__ 幂运算
round(num) __round__ 四舍五入
num.__sizeof__() __sizeof__ 内部表示的字节数
str(num) __str__ 字符串强制转换
num - num2 __sub__ 减法
math.trunc(num) __trunc__ 截断

整数特定方法和操作

操作 由提供 结果
num & num2 __and__ 按位与
math.ceil(num) __ceil__ 上取整
math.floor(num) __floor__ 下取整
hex(num) __hex__ 十六进制转换
~num __invert__ 按位取反
num << num2 __lshift__ 左移
num &#124; num2 __or__ 按位或
num >> num2 __rshift__ 右移
num ^ num2 __xor__ 按位异或
num.bit_length() bit_length 所需位数

浮点数特定方法和操作

操作 结果
f.as_integer_ratio() 返回 num, denom 元组
f.is_integer() 是否为整数

字符串

Python 2 字符串保存字节字符串。要创建 Unicode 字符串,需要使用 Unicode 文本。Python 有几种表示字符串的方式:

字符串类型

类型 示例
字符串 "hello\tthere"
字符串 'hello'
字符串 '''He said, "hello"'''
Unicode 字符串 u'Hello again'
原始字符串 r'hello\tthere'

转义字符Unicode 转义必须在 Unicode 文本中)

转义序列 输出
\ 换行 忽略三引号字符串中的结尾换行符
\\ 反斜杠
\' 单引号
\" 双引号
\a ASCII 响铃
\b ASCII 退格
\n 换行
\r ASCII 回车
\t 制表符
\u12af Unicode 16 位
\U12af89bc Unicode 32 位
\N{BLACK STAR} Unicode 名称
\o84 八进制字符
\xFF 十六进制字符

字符串操作

操作 由提供 结果
s + s2 __add__ 字符串连接
"foo" in s __contains__ 成员关系
s == s2 __eq__ 相等性
s >= s2 __ge__ 大于或等于
s[0] __getitem__ 索引操作
s > s2 __gt__ 大于
s <= s2 __le__ 小于或等于
len(s) __len__ 长度
s < s2 __lt__ 小于
s % (1, 'foo') __mod__ 格式化
s * 3 __mul__ 重复
s != s2 __ne__ 不等于
repr(s) __repr__ 程序员友好字符串
s.__sizeof__() __sizeof__ 内部表示的字节
str(s) __str__ 用户友好字符串

字符串方法

操作 结果
s.capitalize() 字符串首字母大写
s.center(w, [char]) w个空格中居中字符串,使用char(默认为`" "
s.count(sub, [start, [end]]) 计算substartend之间的s中出现次数
s.decode(encoding, errors= 'strict') 将(字节)字符串解码为 Unicode 字符串
s.encode(encoding, errors= 'strict') Unicode字符串编码为字节字符串
s.endswith(sub) 检查是否有后缀
s.expandtabs( tabsize=8) 用空格替换制表符
s.find(sub, [start, [end]]) 查找子字符串或返回-1
s.format(*args, **kw) 格式化字符串
s.index(sub, [start, [end]]) 查找子字符串或引发ValueError
s.isalnum() 是否为字母数字
s.isalpha() 是否为字母
s.isdecimal() 是否为十进制数
s.isdigit() 是否为数字
s.isidentifier() 是否为有效标识符
s.islower() 是否为小写
s.isspace() 是否为空格
s.istitle() 是否为标题化
s.isupper() 是否为大写
s.join(iterable) 返回插入在序列之间的字符串
s.ljust(w, [char]) w个空格中左对齐,使用char(默认为' '
s.lower() 小写
s.lstrip([chars]) 左侧去除chars(默认为空格)
s.partition(sub) 在第一次出现子字符串处拆分字符串,返回(before, sub, after)
s.replace(old, new, [count]) 用新字符串替换子字符串
s.rfind(sub, [start, [end]]) 查找最右侧子字符串或返回-1
s.rindex(sub, [start, [end]]) 查找最右侧子字符串或引发ValueError
s.rjust(w, [char) w个空格中右对齐,使用char(默认为`" "
s.rpartition(sub) 最右侧分区
s.rsplit([sep, [maxsplit=-1]) 由分隔符右侧拆分(默认为空格)
s.rstrip([chars]) 右侧去除
s.split([sep, [maxsplit=-1]]) 将字符串分割成围绕子字符串的序列
s.splitlines( keepends=False) 在行边界处断开字符串
s.startswith( prefix, [start, [end]]) 检查是否有前缀
s.strip([chars]) 移除前导和尾随空格(默认)或chars
s.swapcase() 交换字符串大小写
s.title() 标题化字符串
s.translate(table) 使用翻译表替换字符串
s.upper() 大写
s.zfill(width) 左侧填充0,使字符串填充到width(不截断)

列表

列表是有序的可变序列:

>>> people = ['Paul', 'John', 'George']
>>> people.append('Ringo')

in操作符对于在序列上检查成员资格很有用:

>>> 'Yoko' in people
False

如果我们需要在迭代过程中获取索引号,enumerate函数会给我们一个索引、项对的元组:

>>> for i, name in enumerate(people, 1):
...     print '{} - {}'.format(i, name)
1 - Paul
2 - John
3 - George
4 - Ringo

大多数序列还支持索引操作:

>>> people[0]
'Paul'
>>> people[-1]  # len(people) - 1
'Ringo'

大多数序列也支持切片操作:

>>> people[1:2]
['John']
>>> people[:1]   # Implcit start at 0
['Paul']
>>> people[1:]   # Implcit end at len(people)
['John', 'George', 'Ringo']
>>> people[::2]  # Take every other item
['Paul', 'George']
>>> people[::-1] # Reverse sequence
['Ringo', 'George', 'John', 'Paul']

列表操作

操作 结果
l + l2 __add__ 列表连接(参见.extend
"name" in l __contains__ 成员关系
del l[idx] __del__ 删除索引idx处的项目(参见.pop
l == l2 __eq__ 相等性
"{}".format(l) __format__ 列表的字符串格式
l >= l2 __ge__ 大于或等于。从左边比较列表中的项目
l[idx] __getitem__ 索引操作
l > l2 __gt__ 大于。从左边比较列表中的项目
无哈希 __hash__ 设为None以确保无法在字典中插入
l += l2 __iadd__ 增量(修改l)连接
l *= 3 __imul__ 增量(修改l)重复
for thing in l: __iter__ 迭代
l <= l2 __le__ 小于或等于。从左边比较列表中的项目
len(l) __len__ 长度
l < l2 __lt__ 小于。从左边比较列表中的项目
l * 2 __mul__ 重复
l != l2 __ne__ 不等于
repr(l) __repr__ 程序员友好的字符串
reversed(l) __reversed__ 反转
foo * l __rmul__ 如果foo没有实现__mul__则调用
l[idx] = 'bar' __setitem__ 索引操作以设置值
l.__sizeof__() __sizeof__ 内部表示的字节数
str(l) __str__ 用户友好的字符串

列表方法

操作 结果
l.append(item) 在末尾追加item
l.clear() 空列表(修改l
l.copy() 浅拷贝
l.count(thing) thing出现的次数
l.extend(l2) 列表连接(修改l
l.index(thing) thing的索引,否则ValueError
l.insert(idx, bar) 在索引idx处插入bar
l.pop([idx]) 删除最后一项或索引idx处的项
l.remove(bar) 删除首次出现的bar,否则ValueError
l.reverse() 反转(修改l
l.sort([key=], reverse=False) 就地排序,可选的key函数(修改l

字典

字典是可变的键值映射。键必须是可散列的,但值可以是任何对象:

>>> instruments = {'Paul': 'Bass',
...                'John': 'Guitar'}

>>> instruments['George'] = 'Guitar'
>>> 'Ringo' in instruments
False

>>> for name in instruments:
...     print '{} - {}'.format(name,
...           instruments[name])
Paul - Bass
John - Guitar
George - Guitar

魔术字典方法

操作 结果
key in d __contains__ 成员关系
del d[key] __delitem__ 删除键
d == d2 __eq__ 相等性。字典相等或不相等
"{}".format(d) __format__ 字典的字符串格式
d[key] __getitem__ 获取key的值(参见.get
for key in d: __iter__ 遍历键
len(d) __len__ 长度
d != d2 __ne__ 不等于
repr(d) __repr__ 程序员友好的字符串
d[key] = value __setitem__ key设置value
d.__sizeof__() __sizeof__ 内部表示的字节

字典方法

操作 结果
d.clear() 删除所有项目(改变d
d.copy() 浅复制
d.fromkeys(iter, value=None) 从可迭代对象创建字典,并将值设置为指定值
d.get(key, [default]) 获取key的值或返回默认值(None<EFBFBD><EFBFBD>
d.items() 键值对列表
d.keys() 键列表
d.pop(key, [default]) 返回键的值或默认值(如果未设置则为KeyError
d.popitem() 返回任意(键,值)元组。如果为空则为KeyError
d.setdefault(k, [default]) 执行d.get(k, default)。如果缺少k,则设置为默认值
d.values() 值列表

元组

元组是不可变序列。通常用于存储记录类型数据:

>>> member = ('Paul', 'Bass', 1942)
>>> member2 = ('Ringo', 'Drums', 1940)

注意,通常不需要括号:

>>> row = 1, 'Fred'     # 2 item tuple
>>> row2 = (2, 'Bob')   # 2 item tuple
>>> row3 = ('Bill')     # String!
>>> row4 = ('Bill',)    # 1 item tuple
>>> row5 = 'Bill',      # 1 item tuple
>>> row6 = ()           # Empty tuple

命名元组可用于替代普通元组,并允许向位置成员添加上下文(或名称)。创建它们的语法有点不同,因为我们首先动态创建一个类(因此变量大写):

>>> from collections import namedtuple
>>> Member = namedtuple('Member',
...     'name, instrument, birth_year')
>>> member3 = Member('George', 'Guitar', 1943)

我们可以通过位置或名称访问成员(名称使我们更加明确):

>>> member3[0]
'George'

>>> member3.name
'George'

元组方法

操作 由此提供 结果
t + t2 __add__ 元组连接
"name" in t __contains__ 成员资格
t == t2 __eq__ 相等
"{}".format(t) __format__ 元组的字符串格式
t >= t2 __ge__ 大于或等于。从左边比较元组中的项目
t[idx] __getitem__ 索引操作
t > t2 __gt__ 大于。从左边比较元组中的项目
hash(t) __hash__ 用于集合/字典插入
for thing in t: __iter__ 迭代
t <= t2 __le__ 小于或等于。从左边比较元组中的项目
len(t) __len__ 长度
t < t2 __lt__ 小于。从左边比较元组中的项目
t * 2 __mul__ 重复
t != t2 __ne__ 不相等
repr(t) __repr__ 程序员友好的字符串
foo * t __rmul__ 如果foo没有实现__mul__则调用
t.__sizeof__() __sizeof__ 内部表示的字节
str(t) __str__ 用户友好的字符串

元组方法

操作 结果
t.count(item) 项目的计数
t.index(thing) thing的索引,否则ValueError

集合

集合是一种可变的无序集合,不能包含重复项。集合用于去除重复项和测试成员资格:

>>> digits = [0, 1, 1, 2, 3, 4, 5, 6,
...     7, 8, 9]
>>> digit_set = set(digits)   # remove extra 1

>>> 9 in digit_set
True

集合非常有用,因为它们提供集合操作,如并集(|)、交集(&)、差集(-)和异或(^

>>> odd = {1, 3, 5, 7, 9}
>>> prime = set([2, 3, 5, 7])
>>> even = digit_set - odd
>>> even
set([0, 8, 2, 4, 6])

>>> prime & even  # in intersection
set([2])

>>> odd | even    # in both
set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

>>> even ^ prime  # not in both
set([0, 3, 4, 5, 6, 7, 8])

注意

空集合没有文字语法。您需要使用:

>>> empty = set()

集合方法

操作/方法 由此提供 结果
s & s2 __and__ 集合交集(参见 .intersection
"name" in s __contains__ 成员关系
s == s2 __eq__ 相等性。集合是否相等或不相等
"{}".format(s) __format__ 集合的字符串格式
s >= s2 __ge__ s 包含于 s2 中(参见 .issuperset
s > s2 __gt__ 大于。始终为 False
没有哈希 __hash__ 设置为 None 以确保不能将其插入字典
s &= s2 __iand__ 增强(修改s)交集(参见 .intersection_udpate
s &#124;= s2 __ior__ 增强(修改s)联合(参见 .update
s -= s2 __isub__ 增强(修改s)差集(参见 .difference_update
for thing in s: __iter__ 迭代
s ^= s2 __ixor__ 增强(修改s)异或(参见 .symmetric_difference_update
s <= s2 __le__ s2 包含于 s 中(参见 .issubset
len(s) __len__ 长度
s < s2 __lt__ 小于。始终为 False
s != s2 __ne__ 不相等
s &#124; s2 __or__ 集合并集(参见 .union
foo & s __rand__ 如果 foo 没有实现 __and__ 则调用
repr(s) __repr__ 程序员友好的字符串
foo &#124; s __ror__ 如果 foo 没有实现 __or__ 则调用
foo - s __rsub__ 如果 foo 没有实现 __sub__ 则调用
foo ^ s __rxor__ 如果 foo 没有实现 __xor__ 则调用
s.__sizeof__() __sizeof__ 内部表示的字节
str(s) __str__ 用户友好的字符串
s - s2 __sub__ 集合差集(参见 .difference
s ^ s2 __xor__ 集合异或(参见 .symmetric_difference

集合方法

操作/方法 结果
s.add(item) item 添加到 s 中(修改s
s.clear() s中移除元素(修改s
s.copy() 浅拷贝
s.difference(s2) 返回集合中存在于s而不在s2中的元素的集合
s.difference_update(s2) s中移除s2的项目(修改s
s.discard(item) s中移除 item(修改s)。不会在找不到 item 时引发错误
s.intersection(s2) 返回两个集合中都存在的元素的集合
s.intersection_update(s2) 使用s2的成员更新s(修改s
s.isdisjoint(s2) 如果没有交集则为 True
s.issubset(s2) s 中的所有元素都在 s2
s.issuperset(s2) s2 中的所有元素都在 s
s.pop() s中移除任意项(修改s)。找不到 item 时引发 KeyError
s.remove(item) s中移除 item(修改s)。找不到 item 时引发 KeyError
s.symmetric_difference(s2) 返回仅存在于其中一个集合中的元素的集合
s.symmetric_difference_update(s2) 使用仅存在于其中一个集合中的元素更新s(修改s
s.union(s2) 返回两个集合的所有元素
s.update(s2) 使用两个集合的所有元素更新s(修改s

内置函数

在默认命名空间中,您可以访问各种可调用对象:

内置可调用对象

操作 结果
abs(x) 绝对值协议(调用x.__abs__()
all(seq) 布尔检查seq中所有项目是否为真值
any(seq) 布尔检查seq中是否至少有一个项目为真值
apply(callable, [args, [kwargs]) 调用callable(*args, **kwargs)
bin(i) 包含数字的二进制版本的字符串(int(bin(i), 2)可逆)
bool(x) 布尔协议(调用x.__nonzero__()然后x.__len__()
buffer(obj, [offset, [size]) obj创建缓冲区对象
bytearray(x) 从整数可迭代对象、文本字符串、字节、整数创建可变字节数组,或者不传任何内容以创建空字节数组
bytes(x) 从整数可迭代对象、文本字符串、字节、整数创建不可变字节,或者不传任何内容以创建空字节
callable(x) 检查是否可以执行x()(即x.__call__存在)
chr(i) 将整数码点转换为 Unicode 字符串(ord(chr(i))可逆)
@classmethod 用于装饰方法,以便可以在类上调用它
cmp(a, b) 如果a <、= 或 > b,则返回-1、0 或 1
coerce(num1, num2) 将数字强制转换为公共类型
compile(source, fname, mode) source编译为代码(fname用于错误,modeexec:模块,single:语句,eval:表达式)。可以在表达式上运行eval(code),在语句上运行exec(code)
complex(i, y) 创建复数
copyright Python 版权字符串
credits Python 鸣谢字符串
delattr(obj, attr) obj中删除属性(del obj.attr
dict([x]) 从映射、k、v 元组的可迭代对象、命名参数创建字典,或者不传任何内容以创建空字典
dir([obj]) 列出obj的属性如果没<EFBFBD><EFBFBD>提供obj,则列出当前命名空间中的名称
divmod(num, denom) 返回num//denomnum%denom的元组对
enumerate(seq, [start]) 返回索引、项目元组对的迭代器。索引从start0(默认)开始
eval(source, globals=None, locals=None) 使用全局变量和局部变量运行source(表达式字符串或compile的结果)
execfile(filename, globals=None, locals=None) 使用全局变量和局部变量在filename中运行代码
exit(code) 退出 Python 解释器并返回代码
file(name, [mode, [buffering]]) 以指定模式打开文件
filter([function], seq) 返回满足function(item)为真值的项目的迭代器(如果缺少function,则item为真值)
float(x) 将字符串或数字转换为浮点数(调用x.__float__()
format(obj, fmt) 格式化协议(调用obj.__format__(fmt)
frozenset([seq]) seq创建frozenset(如果缺少则为空)
getattr(obj, attr) obj获取属性(obj.attr
globals() 返回当前全局变量的可变字典
hasattr(obj, attr) 检查obj上的属性是否存在(obj.attr不会引发AttributeError
hash(x) 对象的哈希值协议(调用x.__hash__()
help([x]) 启动交互式帮助(如果没有x),或打印x的文档
hex(i) 包含数字的十六进制版本的字符串(int(hex(i), 16)可逆转)
id(x) x的标识
input([prompt]) 从标准输入读取字符串
int(x, [base=10]) 从数字或字符串创建整数
intern(s) 在全局表中国际化字符串
isinstance(obj, class_or_tuple) 检查obj是否是class_or_tuple的实例或子类的布尔值
issubclass(cls, class_or_tuple) 检查cls是否是类或派生自class_or_tuple的布尔值
iter(seq) 迭代协议(调用seq.__iter__()
len(seq) 序列中的项目数
license() 显示 Python 许可证
list([seq]) seq转换为列表(如果缺失则为空)
locals() 返回本地属性的字典(不像globals,在变异时不保证更新命名空间)
long(num) num强制转换为长整型
map(function, *seqs) seqs中的项目调用function(item)(如果是单个序列)或function(seqs[0][0], seqs[1][0]...)
max(seq, *, [default], [key]) seq中返回最大值。default(如果seq为空时的值)和key(确定大小的函数)是关键字参数。
memoryview(obj) obj创建memoryview
min(seq, *, [default], [key]) seq中返回最小值。default(如果seq为空时的值)和key(确定大小的函数)是关键字参数。
next(iter, [default]) 从迭代协议中获取下一个项目(调用iter.next()),如果提供default,则返回而不是引发StopIteration
object 根基类型
oct(i) 包含数字的八进制版本的字符串(int(oct(i), 8)可逆转)
open(filename, [mode], [buffereing]) 打开文件
ord(s) 将 Unicode 字符串转换为整数码点(chr(ord(s))可逆转)
pow(num, exp, [z]) 幂协议(调用num.__pow__(exp, z)num ** expnum ** exp % z
print val, [val2 ...][,] 将值打印到标准输出。打印协议(调用val.__str__()
@property 将方法转换为属性的装饰器
quit() 退出解释器
range([start], stop, [step]) 返回从start(默认为0)到stop - 1的列表,步长为step(默认为1
raw_input([prompt]) 从用户读取输入
reduce(f, seq, [initial]) 通过在seq的初始对上调用f来执行减少,然后结果与下一个值一起。
reload(module) 重新加载模块(不会替换模块中现有类的实例)
repr(x) 表示协议(调用x.__repr__()
reversed(seq) 反向迭代器
round(num, [ndigits=0]) 四舍五入到ndigits协议(调用num.__round__()
set([seq]) seq创建set(如果缺失则为空)
setattr(obj, attr, val) obj上设置属性(obj.attr = val
slice([start], stop, [step]) 创建slice对象
sorted(seq, * [key=None], [reverse=False]) 按升序排列的列表(使用key函数自定义排序属性)
@staticmethod 用于装饰一个方法,以便您可以在类或实例上调用它
str(obj) 创建字符串(调用obj.__str__()
str(bytes, [encoding], [errors]) 从字节创建字符串(errors默认为strict
sum(seq, [start=0]) seq中的值求和(使用start作为初始值)
super(type, [obj]) 获取超类访问权限
tuple([seq]) seq转换为元组(如果缺失则为空)
type(name, bases, dict) 创建一个新的name类型,具有基类bases和属性dict
type(obj) 返回obj的类型
unichr(num) 从整数num返回 Unicode 字符串
unicode(s) 强制将s转换为 Unicode 字符串
xrange([start], stop, [step]) 返回从start(默认为0)到stop-1,以step增量(默认为1)迭代的范围对象
zip(seq1, [seq2, ...]) 返回元组列表(seq1[0], seq2[0])(seq1[1], seq2[1])...直到最短序列为止

Unicode

Python 2 表示字符串字节序列。要创建一个带有 Unicode 字符的文字 Unicode 字符串,我们需要在字符串前面加上u。我们可以编码Unicode 字符串为一系列字节,比如 UTF-8。如果我们有一个普通字符串字节我们可以解码它们为 Unicode 字符串:

>>> x_sq = u'x²'
>>> x_sq.encode('utf-8')
'x\xc2\xb2'

>>> utf8_bytes = 'x\xc2\xb2'
>>> utf8_bytes.decode('utf-8')
u'x\xb2'  # this is the repr

如果我们调用print,我们将看到用户友好的表示(调用__str__而不是__repr__

>>> print utf8_bytes.decode('utf-8')
x²

如果您有 Unicode 字形,可以直接使用。或者,您可以使用\u后跟 16 位十六进制值 xxxx 输入代码点。对于更大的代码点,请使用\U后跟 xxxxxxxx。如果您有 Unicode 名称通过<E9809A><E8BF87><EFBFBD>unicode.org 上查看表格获得),您可以使用\N语法。以下是等效的:

>>> result = u'x²'
>>> result = u'x\u00b2'
>>> result = u'x\N{SUPERSCRIPT TWO}'
>>> result = u'x\xb2'

../Images/uniencode2.png

描述编码Unicode 字符串为字节表示的图像。在这种情况下,我们转换为 UTF-8。对于这个字符串还有其他字节编码。如果我们有一个 UTF-8 字节字符串,我们可以解码它为 Unicode 字符串。请注意,我们应该明确解码,因为可能有其他编码可以解码为可能给我们错误数据或乱码的 Unicode 字符串。

字符串格式化

大多数现代 Python 代码使用.format方法PEP 3101从其他部分创建字符串。格式方法使用{}作为占位符。

在占位符内,我们可以提供不同的说明符:

  • {0} - 参考第一个位置参数

  • {} - 参考隐式位置参数

  • {result} - 参考关键字参数

  • {bike.tire} - 参考参数的属性

  • {names[0]} - 参考参数的第一个元素

>>> person = {'name': 'Paul',
...     'instrument': 'Bass'}
>>> inst = person['instrument']

>>> print "Name: {} plays: {}".format(
...     person['name'], inst)
Name: Paul plays: Bass

或:

>>> print "Name: {name} " \
...       "plays: {inst}".format(
...       name=person['name'], inst=inst)
Name: Paul plays: Bass

转换标志

您可以在占位符内提供转换标志

  • !s - 对参数调用str()

  • !r - 对参数调用repr()

>>> class Cat(object):
...     def __init__(self, name):
...         self.name = name
...     def __format__(self, data):
...         return "Format"
...     def __str__(self):
...         return "Str"
...     def __repr__(self):
...         return "Repr"

>>> cat = Cat("Fred")
>>> print "{} {!s} {!r}".format(cat, cat, cat)
Format Str Repr

格式规范

您可以在冒号后提供格式规范。格式规范的语法如下:

[[fill]align][sign][#][0][width][grouping_option]
[.precision][type]

以下表列出了字段含义:

Field Meaning
fill 使用align填充空格
align <-左对齐,>-右对齐,^-居中对齐,=-在符号后放置填充
sign +-对所有数字,--仅对负数,空格-正数前导空格,负数符号
# 前缀整数。Ob-二进制,0o-八进制,0x-十六进制
0 启用零填充
width 最小字段宽度
grouping_option ,-使用逗号作为千位分隔符,_-使用下划线作为千位分隔符
.precision 小数点后的数字(浮点数)。最大字符串长度(非数字)
type s-字符串格式(默认)参见整数和浮点图表

下表列出了我们用于格式化整数和浮点数的各种选项。

整数类型 含义
b 二进制
c 字符 - 转换为 Unicode 字符
d 十进制(默认)
n 具有区域设置特定分隔符的十进制
o 八进制
x 十六进制(小写)
X 十六进制(大写)
浮点类型 含义
--- ---
e/E 指数。小写/大写 e
f 固定点
g/G 通用。对于大和小数字的固定指数(g默认)
n 具有区域设置特定分隔符的g
% 百分比(乘以 100

一些format示例

这里有一些使用.format的示例。让我们将一个字符串格式化在*包围的 12 个字符中心。*填充字符,^对齐字段,12宽度字段:

>>> "Name: {:*¹²}".format("Ringo")
'Name: ***Ringo****'

接下来,我们使用宽度为 10一位小数点和符号在宽度填充之前的百分比格式化。=对齐字段,10.1宽度精度字段,%浮点类型,将数字转换为百分比:

>>> "Percent: {:=10.1%}".format(-44./100)
'Percent: -    44.0%'

下面是二进制和十六进制转换。整数类型字段分别设置为bx

>>> "Binary: {:#b}".format(12)
'Binary: 0b1100'

>>> "Hex: {:#x}".format(12)
'Hex: 0xc'

文件

open函数将接受文件路径和模式作为输入,并返回文件句柄。根据内容和需求,有各种模式可以打开文件。如果以二进制模式打开文件,将得到字节。在文本模式下,将得到字符串:

Mode 含义
'r' 读取文本文件(默认)
'rU' 读取文本文件。将\r\n\r\n视为\n
'w' 写入文本文件(如果存在则截断)
'a' 追加到文本文件(写入末尾)
'rb' 读取二进制文件
'wb' 写入二进制文件(截断)
'w+b' 以读写方式打开二进制文件
'ab' 追加到二进制文件(写入末尾)

写入文件

我们使用文件的上下文管理器来确保在上下文块退出时关闭文件。

>>> with open('/tmp/names.txt', 'w') as fout:
...     fout.write('Paul\r\nJohn\n')
...     fout.writelines(['Ringo\n', 'George\n'])

读取文件

打开文本文件后,您可以迭代处理行。这样可以节省内存,因为需要时才读取行:

>>> with open('/tmp/names.txt') as fin:
...     for line in fin:
...         print repr(line)
'Paul\r\n'
'John\n'
'Ringo\n'
'George\n'

文件方法/属性

操作 结果
f.__iter__() 支持迭代
f.__repr__() repr(f) 的实现
f.close() 关闭文件
f.closed 是否已关闭
f.encoding 文件的编码
f.errors 编码的错误模式(默认为'strict'
f.fileno() 返回文件描述符
f.flush() 写入文件缓冲区
f.isatty() 是否为交互式文件
f.mode 文件模式
f.name 文件名
f.newlines 遇到的行结束字符(元组或字符串)
f.next() 返回迭代的下一个项(文本中的行)
f.softspace 是否需要打印空格的标志
f.read( size=-1) 读取 size 个字符(-1 为整个文件)
f.readinto() 神秘的方法
f.readline( size=-1) 从行中读取 size 个字符(-1 为整行)
f.readlines( hint=-1) 从文件中读取少于 hint 个字符的行(-1 为整个文件)
f.seek(cookie, whence=0) 将流位置更改为距离 whence0 - 起始,1 - 当前位置,2 - 结尾)的 cookie 字节(可以为负数)偏移。
f.tell() 当前流位<EFBFBD><EFBFBD><EFBFBD>
f.truncate( pos=None) 截断文件至 pos 字节
f.write(text) text 写入文件
f.writelines( lines) lines 写入文件(如果需要换行,请提供)

函数

定义函数

函数可能接受输入,进行一些处理,并可能返回输出。你可以在函数名和参数后直接提供文档字符串:

>>> def add_numbers(x, y):
...     """ add_numbers sums up x and y
...
...     Arguments:
...     x -- object that supports addition
...     y -- object that supports addition
...     """
...     return x + y

注意

我们在 Python 中使用空格来指定一个块。通常在冒号后缩进。PEP 8 建议使用 4 个空格。

我们可以使用 lambda 语句创建匿名函数。因为这只允许表达式,所以在功能上有些受限:

>>> add = lambda x, y: x + y
>>> add(4, 5)
9

函数可以有默认参数。在这里要小心可变类型,因为默认值在函数创建时绑定,而不是在调用时:

>>> def add_n(x, n=42):
...     return x + n

>>> add_n(10)
52
>>> add_n(3, -10)
-7

函数可以支持可变位置参数:

>>> def add_many(*args):
...     result = 0
...     for arg in args:
...          result += arg
...     return result

>>> add_many()
0
>>> add_many(1)
1
>>> add_many(42, 3.14)
45.14

函数可以支持可变关键字参数:

>>> def add_kwargs(**kwargs):
...     result = 0
...     for key in kwargs:
...         result += kwargs[key]
...     return result

>>> add_kwargs(x=1, y=2, z=3)
6

>>> add_kwargs()
0

>>> add_kwargs(4)
Traceback (most recent call last):
  ...
TypeError: add_kwargs() takes exactly 0 arguments
(1 given)

调用函数

你也可以使用 ***解包 序列和字典参数:

>>> def add_all(*args, **kwargs):
...     """Add all arguments"""
...     result = 0
...     for num in args + tuple(kwargs.values()):
...         result += num
...     return result

>>> sizes = (2, 4.5)
>>> named_sizes = {"this": 3, "that": 1}

以下两个示例是等价的:

>>> add_all(*sizes)
6.5

>>> add_all(sizes[0], sizes[1])
6.5

以下两个示例是等价的:

>>> add_all(**named_sizes)
4

>>> add_all(this=3, that=1)
4

你也可以在调用时结合 ***

>>> add_all(*sizes, **named_sizes)
10.5

获取帮助

你可以通过使用 help 来获取有文档字符串的函数的帮助:

>>> help(add_all)
Help on function add_all in module __main__:

add_all(*args, **kwargs)
    Add all arguments

Python 支持面向对象编程,但不要求你创建类。你可以有效地使用内置数据结构。这里是一个简单自行车的类。类属性 num_passengers 是所有 Bike 实例共享的。实例属性 sizeratio 对每个实例都是唯一的:

>>> class Bike(object):
...     ''' Represents a bike '''
...     num_passengers = 1   # class attribute
...
...     def __init__(self, wheel_size,
...                  gear_ratio):
...         ''' Create a bike specifying the
...         wheel size, and gear ratio '''
...         # instance attributes
...         self.size = wheel_size
...         self.ratio = gear_ratio
...
...     def gear_inches(self):
...         return self.ratio * self.size

我们可以通过调用构造函数(__init__)来调用类名。请注意,self 是实例,但 Python 会自动为我们传递它:

>>> bike = Bike(26, 34./13)
>>> print bike.gear_inches()
68.0

我们可以在实例上访问类属性或实例属性:

>>> bike.num_passengers
1

>>> bike.size
26

如果在实例上找不到属性Python 将在类上查找,它将继续查找父类以尝试找到它。如果查找不成功,将引发AttributeError

子类

要创建一个类的子类,只需在声明中的类名后面的括号中放置父类名。我们可以调用super函数来访问父类方法:

>>> class Tandem(Bike):
...     num_passengers = 2
...
...     def __init__(self, wheel_size, rings, cogs):
...         self.rings = rings
...         self.cogs = cogs
...         ratio = rings[0] / float(cogs[0])
...         super(Tandem, self).__init__(wheel_size, ratio)
...
...     def shift(self, ring_idx, cog_idx):
...         self.ratio = self.rings[ring_idx] \
...              / float(self.cogs[cog_idx])
...

注意

在上面的示例中,我们使用\来表示该行在下一行继续。除非有一个未关闭的隐式行继续与未关闭的开放括号((, [, 或 {),否则通常需要这样做。

注意

super函数在旧式类中不起作用。确保你的基类在 Python 2 中继承自object

子类的实例可以调用在其类或父类上定义的方法:

>>> tan = Tandem(26, [42, 36], [24, 20, 15, 11])
>>> tan.shift(1, -1)
>>> tan.gear_inches()
85.0909090909091

类方法和静态方法

classmethod装饰器用于创建可以直接在类上调用的方法。这允许我们创建替代构造函数。请注意,隐式的第一个参数是类,通常命名为cls(因为class是一个关键字,会报错):

>>> INCHES_PER_METER = 39.37

>>> class MountainBike(Bike):
...     @classmethod
...     def from_metric(cls, size_meters, ratio):
...          return cls(size_meters *
...                     INCHES_PER_METER,
...                     ratio)

>>> mtn = MountainBike.from_metric(.559, 38./11)
>>> mtn.gear_inches()
76.0270490909091

注意

在上面的示例中,我们有一个隐式的行继续,没有反斜杠,因为该行有一个(

staticmethod装饰器允许你将函数附加到一个类上。(我不喜欢它们,只需使用一个函数)。请注意,它们不会得到一个隐式的第一个参数。它可以在实例或类上调用:

>>> class Recumbent(Bike):
...     @staticmethod
...     def is_fast():
...         return True

>>> Recumbent.is_fast()
True

>>> lawnchair = Recumbent(20, 4)
>>> lawnchair.is_fast()
True

属性

如果你想在属性访问时在内部执行操作,可以使用属性来实现:

>>> class Person:
...     def __init__(self, name):
...         self._name = name
...
...     @property
...     def name(self):
...         if self._name == 'Richard':
...             return 'Ringo'
...         return self._name
...
...     @name.setter
...     def name(self, value):
...         self._name = value
...
...     @name.deleter
...     def name(self):
...         del self._name

而不是调用.name()方法,我们访问属性:

>>> p = Person('Richard')
>>> p.name
'Ringo'

>>> p.name = 'Fred'

循环

你可以循环遍历序列中的对象:

>>> names = ['John', 'Paul', 'Ringo']
>>> for name in names:
...    print name
John
Paul
Ringo

break语句将使你跳出循环:

>>> for name in names:
...    if name == 'Paul':
...        break
...    print name
John

continue语句跳过循环体,继续下一个迭代项:

>>> for name in names:
...    if name == 'Paul':
...        continue
...    print name
John
Ringo

你可以使用else语句表示每个项都被遍历,并且没有遇到break

>>> for name in names:
...     if name == 'George':
...          break
... else:
...     raise ValueError("No Georges")
Traceback (most recent call last):
  ...
ValueError: No Georges

不要遍历索引值(range(len(names)))。使用enumerate

>>> for i, name in enumerate(names, 1):
...     print "{}. {}".format(i, name)
1\. John
2\. Paul
3\. Ringo

while循环

你也可以使用while循环来创建循环。如果是无限循环,你可以跳出它:

>>> done = False
>>> while not done:
...     # some work
...     done = True

迭代协议

使迭代器实现__iter__next

>>> class fib:
...     def __init__(self, limit=None):
...         self.val1 = 1
...         self.val2 = 1
...         self.limit = limit
...
...     def __iter__(self):
...         return self
...
...     def next(self):
...         val = self.val1
...         self.val1 = self.val2
...         self.val2 = val + self.val1
...         if self.limit is not None and \
...             val < self.limit:
...             return val
...         raise StopIteration

在循环中使用迭代器:

>>> e = fib(6)
>>> for val in e:
...    print val
1
1
2
3
5

展开协议:

>>> e = fib(6)
>>> it = iter(e)  # calls e.__iter__()
>>> next(it)      # calls it.next()
1
>>> next(it)
1
>>> next(it)
2
>>> next(it)
3
>>> next(it)
5
>>> next(it)
Traceback (most recent call last):
  ...
StopIteration

条件语句

Python 有一个带有零个或多个elif语句的if语句,并在最后有一个可选的else语句。在 Python 中,elif一词是荷兰语,意为else if

>>> grade = 72

>>> def letter_grade(grade):
...     if grade > 90:
...         return 'A'
...     elif grade > 80:
...         return 'B'
...     elif grade > 70:
...         return 'C'
...     else:
...         return 'D'

>>> letter_grade(grade)
'C'

Python 支持以下测试:>, >=, <, <=, ==, 和 !=。对于布尔运算符使用andor,和not&|,和^是位运算符)。

注意Python 也支持范围比较

>>> x = 4
>>> if 3 < x < 5:
...     print "Four!"
Four!

Python 没有 switch 语句,通常使用字典来支持类似的结构:

>>> def add(x, y):
...     return x + y

>>> def sub(x, y):
...     return x - y

>>> ops = {'+': add, '-': sub}

>>> op = '+'
>>> a = 2
>>> b = 3
>>> opsop
5

真值性

您可以定义__nonzero__方法来教导您的类在布尔上下文中如何行事。如果不存在Python 将使用__len__,最后默认为True

以下表列出了真值假值

真值 假值
True False
大多数对象 None
1 0
3.2 0.0
[1, 2] [](空列表)
{'a': 1, 'b': 2} {}(空字典)
'string' ""(空字符串)
'False'  
'0'  

短路

如果and语句评估为假,它将会短路:

>>> 0 and 1/0
0

同样,当某个条件为真时,or语句将会短路:

>>> 1 or 1/0
1

三元运算符

Python 有自己的三元运算符,称为条件表达式(参见 PEP 308。这些很方便因为它们可以用于理解构造和lambda函数中:

>>> last = 'Lennon' if band == 'Beatles' else 'Jones'

请注意,这与if语句具有类似的行为但它是一个表达式而不是语句。Python 区分这两者。区分两者的一个简单方法是记住表达式跟随return语句。你可以return的任何东西都是表达式。

异常

Python 可以捕获一个或多个异常PEP 3110。如果您想要有不同的反应可以提供一系列不同的异常来捕获。一些建议

  • 尽量将try语句块保持在引发异常的代码范围内

  • 对于您捕获的异常要具体明确

  • 如果要检查异常,请使用as创建一个指向它的变量

如果在except块中使用裸raisePython 的回溯将指向原始异常的位置,而不是引发异常的位置。

>>> def avg(seq):
...     try:
...         result = sum(seq) / float(len(seq))
...     except ZeroDivisionError as e:
...         return None
...     except Exception:
...         raise
...     return result

>>> avg([1, 2, 4])
2.3333333333333335

>>> avg([]) is None
True

>>> avg('matt')
Traceback (most recent call last):
  ...
TypeError: unsupported operand type(s) for +: 'int'
and 'str'

引发异常

你可以使用raise语句引发异常:

>>> def bad_code(x):
...     raise ValueError('Bad code')

>>> bad_code(1)
Traceback (most recent call last):
  ...
ValueError: Bad code

装饰器

装饰器PEP 318允许我们在调用函数之前和之后插入逻辑。您可以使用一个接受函数作为输入并返回函数作为输出的函数来定义装饰器。这是身份装饰器

>>> def identity(func):
...     return func

我们可以这样装饰一个函数:

>>> @identity
... def add(x, y):
...     return x + y

一个更有用的装饰器可以在调用原始函数之前和之后注入逻辑。为此,我们在函数内部创建一个函数并返回它。下面,我们使用打印函数来说明调用前/后的行为,否则这与身份装饰器非常相似:

>>> import functools
>>> def verbose(func):
...     @functools.wraps(func)
...     def inner(*args, **kwargs):
...         print "Calling with:{} {}".format(args,
...               kwargs)
...         res = func(*args, **kwargs)
...         print "Result:{}".format(res)
...         return res
...     return inner

有一个特殊的语法用于应用装饰器。我们在装饰器名称前面放置@,并将其放在直接在要装饰的函数上面的一行上。在函数声明之前使用@verbose行是对将指向该函数的变量重新赋值的语法糖,以调用装饰器并将函数传递给它的结果:

>>> @verbose
... def sub(x, y):
...     return x - y

这也可以写成sub = verbose(sub)。请注意,我们的装饰函数仍将调用我们的原始函数,但会添加一些print语句:

>>> sub(5, 4)
Calling with:(5, 4) {}
Result:1
1

参数化装饰器

因为我们可以使用闭包来创建函数,我们也可以使用闭包来创建装饰器。这与我们上面的装饰器非常相似,但现在我们制作一个将返回装饰器的函数。根据该函数的输入,我们可以控制(或参数化)装饰器的行为:

>>> def verbose_level(level):
...     def verbose(func):
...         @functools.wraps(func)
...         def inner(*args, **kwargs):
...             for i in range(level):  # parameterized!
...                 print "Calling with:{} {}".format(
...                       args, kwargs)
...             res = func(*args, **kwargs)
...             print "Result:{}".format(res)
...             return res
...         return inner
...     return verbose

当你用带参数的装饰器装饰时,装饰看起来不同,因为我们需要调用函数来创建装饰器:

>>> @verbose_level(2)
... def div(x, y):
...     return x/float(y)

>>> div(1, 5)
Calling with:(1, 5) {}
Calling with:(1, 5) {}
Result:0.2
0.2

类装饰器和类元类

Python 允许你动态创建和修改类。类装饰器和类元类是实现这一点的两种方式。

类装饰器

你可以用类装饰器PEP 3129装饰一个类定义。它是一个以类为输入并返回一个类的函数。

>>> def add_chirp(cls):
...     'Class decorator to add speak method'
...     def chirp(self):
...         return "CHIRP"
...     cls.speak = chirp
...     return cls
...
>>> @add_chirp
... class Bird:
...     pass

>>> b = Bird()
>>> print b.speak()
CHIRP

使用type创建类

你可以使用type来确定对象的类型,但也可以提供名称、父类和属性映射,它将返回一个类。

>>> def howl(self):
...     return "HOWL"

>>> parents = ()
>>> attrs_map = {'speak': howl}
>>> F = type('F', parents, attrs_map)

>>> f = F()
>>> print f.speak()
HOWL

函数与函数元类

在类定义中你可以指定一个元类PEP 3115它可以是一个函数或一个类。这是一个可以改变类的函数的例子。

>>> def meta(name, parents, attrs_map):
...     def bark(self):
...         return "WOOF!"
...     attrs_map['speak'] = bark
...     return type(name, parents, attrs_map)

>>> class Dog(object):
...     __metaclass__ = meta

>>> d = Dog()
>>> print d.speak()
WOOF!

类与类元类

你可以定义一个类装饰器,并使用__new____init__。通常大多数人使用__new__,因为它可以改变像__slots__这样的属性

>>> class CatMeta(type): # Needs to subclass type
...     def __new__(cls, name, parents, attrs_map):
...         # cls is CatMeta
...         # res is the class we are creating
...         res = super(CatMeta, cls).__new__(cls, name,
...             parents, attrs_map)
...         def meow(self):
...             return "MEOW"
...         res.speak = meow
...         return res
...
...     def __init__(cls, name, parents, attrs_map):
...         super(CatMeta, cls).__init__(name, parents, attrs_map)

>>> class Cat(object):
...     __metaclass__ = CatMeta

>>> c = Cat()
>>> print c.speak()
MEOW

生成器

生成器PEP 255是在你迭代它们的结果时暂停其状态的函数。每个yield语句返回迭代的下一个项,然后冻结函数的状态。当恢复迭代时,函数从被冻结的点继续。请注意,调用函数的结果是一个生成器:

>>> def fib_gen():
...     val1, val2 = 1, 1
...     while 1:
...         yield val1
...         val1, val2 = val2, (val1+val2)

我们可以通过使用迭代协议来模拟迭代:

>>> gen = fib_gen()
>>> gen_iter = iter(gen)
>>> next(gen_iter)
1
>>> next(gen_iter)
1
>>> next(gen_iter)
2
>>> next(gen_iter)
3

推导式

理解构造允许我们将 map 和 filter 背后的功能思想结合到易于阅读的单行代码中。当你看到代码在列表(或字典、集合或生成器)中聚合时,可以用列表推导式(或字典、集合推导式或生成器表达式)替换它。这是一个代码异味的例子:

>>> nums = range(10)
>>> result = []
>>> for num in nums:
...     if num % 2 == 0:  # filter
...         result.append(num*num)  # map

这可以用列表推导式PEP 202来指定

>>> result = [num*num for num in nums
...           if num % 2 == 0]

构造列表推导式:

  • 将结果(result)赋给括号。括号向代码读者表明将返回一个列表:

    result = [ ]
    
    
  • for循环结构放在括号内。不需要冒号:

    result = [for num in nums]
    
    
  • 在 for 循环后插入任何过滤累积的操作:

    result = [for num in nums if num % 2 == 0]
    
    
  • 直接在左括号后面插入累积对象(num*num)。如果是元组,则在对象周围插入括号:

    result = [num*num for num in nums
              if num % 2 == 0]
    
    

集合推导式

如果用{替换[你将得到一个集合推导式PEP 274而不是一个列表推导式

>>> {num*num for num in nums if num % 2 == 0}
set([0, 16, 4, 64, 36])

字典推导式

如果用{替换[并用冒号分隔键和值你将得到一个字典推导式PEP 274

>>> {num:num*num for num in nums if num % 2 == 0}
{0: 0, 8: 64, 2: 4, 4: 16, 6: 36}

生成器表达式

如果你将[替换为(,你将得到一个生成器而不是列表。这被称为生成器表达式PEP 289

>>> (num*num for num in nums if num % 2 == 0)
<generator object <genexpr> at 0x10a6f8780>

上下文管理器

如果你发现代码需要在一个块之前和之后确保某些事情发生上下文管理器PEP 343是强制执行的便利方式。另一个表明你可能正在使用上下文管理器的代码异味是try/finally块。

上下文管理器可以通过函数或类创建。

如果我们正在编写一个用于编写 TeX 的 Python 模块,我们可能会这样做以确保环境被正确关闭:

>>> def start(env):
...     return '\begin{}'.format(env)

>>> def end(env):
...      return '\end{}'.format(env)

>>> def may_error():
...     import random
...     if random.random() < .5:
...         return 'content'
...     raise ValueError('Problem')

>>> out = []
>>> out.append(start('center'))

>>> try:
...     out.append(may_error())
... except ValueError:
...     pass
... finally:
...     out.append(end('center'))

这段代码可以使用上下文管理器来变得更加清晰。

基于函数的上下文管理器

要使用函数创建上下文管理器,用contextlib.contextmanager装饰,并在想要包围的地方yield

>>> import contextlib
>>> @contextlib.contextmanager
... def env(name, content):
...     content.append(r'\begin{}'.format(name))
...     try:
...         yield
...     except ValueError:
...         pass
...     finally:
...         content.append(r'\end{}'.format(name))

现在我们的代码看起来更好了,而且总会有一个闭合标签:

>>> out = []
>>> with env('center', out):
...     out.append(may_error())

>>> out
['\\begincenter', 'content', '\\endcenter']

基于类的上下文管理器

要创建基于类的上下文管理器,实现__enter____exit__方法:

>>> class env:
...     def __init__(self, name, content):
...         self.name = name
...         self.content = content
...
...     def __enter__(self):
...         self.content.append(r'\begin{}'.format(
...             self.name))
...
...     def __exit__(self, type, value, tb):
...         # if error in block, t, v, & tb
...         # have non None values
...         # return True to hide exception
...         self.content.append(r'\end{}'.format(
...             self.name))
...         return True

代码看起来与使用基于函数的上下文管理器相同:

>>> out = []
>>> with env('center', out):
...     out.append(may_error())

>>> out  # may_error had an issue
['\\begincenter', '\\endcenter']

上下文对象

一些上下文管理器创建我们可以在上下文中使用的对象。open上下文管理器返回一个文件对象:

with open('/tmp/test.txt') as fin:
    # muck around with fin

要在基于类的上下文管理器中创建一个对象,只需yield该对象。在__enter__方法中返回对象。

<EFBFBD><EFBFBD><EFBFBD>本、包和模块

脚本

一个脚本是一个你在上面调用python的 Python 文件。通常在底部附近有一行看起来像这样的代码:

if __name__ == '__main__':
    # execute something

这个测试允许你在执行代码和导入代码时改变代码路径。当你执行该模块时,模块的__name__属性被设置为'__main__'。否则,如果你导入模块,它将是模块的名称(不带.py)。

模块

模块是以.py结尾的文件。根据 PEP 8我们将模块名小写并且不在它们之间加下划线。任何在PYTHONPATH环境变量或sys.path列表中找到的模块都可以被导入。

一个包含名为__init__.py的文件的目录是一个。一个包可以包含模块以及子包。要导入包,包应该在PYTHONPATHsys.path中找到。一个例子可能是这样的:

packagename/
  __init__.py
  module1.py
  module2.py
  subpackage/
    __init__.py

__init__.py模块可以是空的,也可以从包中的其他模块导入代码,以消除导入语句中的嵌套。

导入

你可以导入一个包或一个模块:

import packagename
import packagename.module1

假设在module1中有一个fib函数。你可以访问你导入的模块的命名空间中的所有内容。要使用这个函数,你需要使用完全限定的名称,packagename.module1.fib

import packagename.module1

packagename.module1.fib()

如果你只想导入fib函数,使用from变体:

from packagename.module1 import fib

fib()

你也可以使用as来重命名导入:

from packagename.module1 import fib as package_fib

package_fib()

环境

Python 2 不包含开箱即用的创建虚拟环境的功能。要安装用于为项目创建沙盒的virtualenv模块,请运行以下命令(可能需要使用sudo运行):

$ pip install virtualenv

在 Unix 和 Windows 系统上创建环境,请运行:

$ virtualenv /path/to/env

要进入或激活Unix 环境,请运行:

$ source /path/to/env/bin/activate

在 Windows 上运行:

c:\>c:\path\to\env\Scripts\activate.bat

你的提示符应该在括号中显示活动虚拟环境的名称。要在两个平台上停用环境,只需运行以下命令:

(env) $ deactivate

安装软件包

现在你应该有一个pip可执行文件,它将从 PyPI [2]安装一个软件包到你的虚拟环境中:

(env) $ pip install django

[2] pypi.python.org/pypi

要卸载软件包,请运行:

(env) $ pip uninstall django

如果安装软件包时遇到问题,您可能需要考虑使用其他 Python 发行版,如 Anaconda [3],其中预先打包了许多难以安装的软件包。

[3] docs.continuum.io/anaconda/