|
|
||
|---|---|---|
| .. | ||
| img | ||
| README.md | ||
| SUMMARY.md | ||
| tiny-py-es6-nb_1.md | ||
| tiny-py-es6-nb_2.md | ||
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 支持的编辑器都可以注释掉一个区域。
重用相同变量的示例
数字
Python 包括三种类型的数字字面量:整数、浮点数 和 复数。
数字类型
| 类型 | 示例 |
|---|---|
| 整数 | 14 |
| 整数(十六进制) | 0xe |
| 整数(八进制) | 0o16 |
| 整数(二进制) | 0b1110 |
| 浮点数 | 14.0 |
| 浮点数 | 1.4e1 |
| 复数 | 14+0j |
有许多用于操作数字的内置函数,如 abs、min、max、ceil。还可以查看标准库中的 math 和 random 模块。
数字魔术方法
| 操作 | 提供者 | 结果 |
|---|---|---|
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 | 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]]) |
计算sub在start和end之间的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 |= 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 | s2 |
__or__ |
集合并集(参见 .union) |
foo & s |
__rand__ |
如果 foo 没有实现 __and__ 则调用 |
repr(s) |
__repr__ |
程序员友好的字符串 |
foo | 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用于错误,mode为exec:模块,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//denom和num%denom的元组对 |
enumerate(seq, [start]) |
返回索引、项目元组对的迭代器。索引从start或0(默认)开始 |
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 ** exp或num ** 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'
描述编码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%'
下面是二进制和十六进制转换。整数类型字段分别设置为b和x:
>>> "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) |
将流位置更改为距离 whence(0 - 起始,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 实例共享的。实例属性 size 和 ratio 对每个实例都是唯一的:
>>> 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 支持以下测试:>, >=, <, <=, ==, 和 !=。对于布尔运算符使用and,or,和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块中使用裸raise,Python 的回溯将指向原始异常的位置,而不是引发异常的位置。
>>> 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的文件的目录是一个包。一个包可以包含模块以及子包。要导入包,包应该在PYTHONPATH或sys.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/ |
|---|

