@@ -5,7 +5,7 @@
|
||||
----------
|
||||
问题
|
||||
----------
|
||||
如果一个可迭代对象的元素个数超过变量个数时,会出现"太多解压值"的异常。
|
||||
如果一个可迭代对象的元素个数超过变量个数时,会抛出一个 ``ValueError`` 。
|
||||
那么怎样才能从这个可迭代对象中解压出N个元素出来?
|
||||
|
||||
|
|
||||
@@ -37,8 +37,8 @@ Python的星号表达式可以用来解决这个问题。比如,你在学习
|
||||
>>> phone_numbers
|
||||
['773-555-1212', '847-555-1212']
|
||||
>>>
|
||||
值得注意的是上面解压出的phone_numbers变量永远都是列表类型,不管解压的电话号码数量是多少(包括0个)。
|
||||
所以,任何使用到phone_numbers变量的代码就不需要做多余的类型检查去确认它是否是列表类型了。
|
||||
值得注意的是上面解压出的 ``phone_numbers`` 变量永远都是列表类型,不管解压的电话号码数量是多少(包括0个)。
|
||||
所以,任何使用到 ``phone_numbers`` 变量的代码就不需要做多余的类型检查去确认它是否是列表类型了。
|
||||
|
||||
星号表达式也能用在列表的开始部分。比如,你有一个公司前8个月销售数据的序列,
|
||||
但是你想看下最近一个月数据和前面7个月的平均值的对比。你可以这样做:
|
||||
@@ -108,8 +108,8 @@ Python的星号表达式可以用来解决这个问题。比如,你在学习
|
||||
'/usr/bin/false'
|
||||
>>>
|
||||
|
||||
有时候,你想解压一些元素后丢弃它们,你不能简单就使用*,
|
||||
但是你可以使用一个普通的废弃名称,比如_或者ign。
|
||||
有时候,你想解压一些元素后丢弃它们,你不能简单就使用 ``*`` ,
|
||||
但是你可以使用一个普通的废弃名称,比如 ``_`` 或者 ``ign`` 。
|
||||
|
||||
代码示例:
|
||||
|
||||
|
||||
@@ -41,10 +41,10 @@
|
||||
----------
|
||||
讨论
|
||||
----------
|
||||
我们在写查询元素的代码时,通常会使用包含yield表达式的生成器函数,也就是我们上面示例代码中的那样。
|
||||
我们在写查询元素的代码时,通常会使用包含 ``yield`` 表达式的生成器函数,也就是我们上面示例代码中的那样。
|
||||
这样可以将搜索过程代码和使用搜索结果代码解耦。如果你还不清楚什么是生成器,请参看4.3节。
|
||||
|
||||
使用deque(maxlen=N)构造函数会新建一个固定大小的队列。当新的元素加入并且这个队列已满的时候,
|
||||
使用 ``deque(maxlen=N)`` 构造函数会新建一个固定大小的队列。当新的元素加入并且这个队列已满的时候,
|
||||
最老的元素会自动被移除掉。
|
||||
|
||||
代码示例:
|
||||
@@ -66,7 +66,7 @@
|
||||
|
||||
尽管你也可以手动在一个列表上实现这一的操作(比如增加、删除等等)。但是这里的队列方案会更加优雅并且运行得更快些。
|
||||
|
||||
更一般的,deque类可以被用在任何你只需要一个简单队列数据结构的场合。
|
||||
更一般的, ``deque`` 类可以被用在任何你只需要一个简单队列数据结构的场合。
|
||||
如果你不设置最大队列大小,那么就会得到一个无限大小队列,你可以在队列的两端执行添加和弹出元素的操作。
|
||||
|
||||
代码示例:
|
||||
@@ -89,5 +89,5 @@
|
||||
>>> q.popleft()
|
||||
4
|
||||
|
||||
在队列两端插入或删除元素时间复杂度都是O(1),而在列表的开头插入或删除元素的时间复杂度为O(N)。
|
||||
在队列两端插入或删除元素时间复杂度都是 ``O(1)`` ,而在列表的开头插入或删除元素的时间复杂度为 ``O(N)`` 。
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ heapq模块有两个函数:``nlargest()`` 和 ``nsmallest()`` 可以完美解
|
||||
cheap = heapq.nsmallest(3, portfolio, key=lambda s: s['price'])
|
||||
expensive = heapq.nlargest(3, portfolio, key=lambda s: s['price'])
|
||||
|
||||
译者注:上面代码在对每个元素进行对比的时候,会以price的值进行比较。
|
||||
译者注:上面代码在对每个元素进行对比的时候,会以 ``price`` 的值进行比较。
|
||||
|
||||
|
|
||||
|
||||
@@ -55,7 +55,7 @@ heapq模块有两个函数:``nlargest()`` 和 ``nsmallest()`` 可以完美解
|
||||
[-4, 2, 1, 23, 7, 2, 18, 23, 42, 37, 8]
|
||||
>>>
|
||||
|
||||
堆数据结构最重要的特征是heap[0]永远是最小的元素。并且剩余的元素可以很容易的通过调用heapq.heappop()方法得到,
|
||||
堆数据结构最重要的特征是 ``heap[0]`` 永远是最小的元素。并且剩余的元素可以很容易的通过调用 ``heapq.heappop()`` 方法得到,
|
||||
该方法会先将第一个元素弹出来,然后用下一个最小的元素来取代被弹出元素(这种操作时间复杂度仅仅是O(N),N是堆大小)。
|
||||
比如,如果想要查找最小的3个元素,你可以这样做:
|
||||
|
||||
@@ -68,13 +68,13 @@ heapq模块有两个函数:``nlargest()`` 和 ``nsmallest()`` 可以完美解
|
||||
>>> heapq.heappop(nums)
|
||||
2
|
||||
|
||||
当要查找的元素个数相对比较小的时候,函数nlargest() 和 nsmallest()是很合适的。
|
||||
当要查找的元素个数相对比较小的时候,函数 ``nlargest()`` 和 ``nsmallest()`` 是很合适的。
|
||||
如果你仅仅想查找唯一的最小或最大(N=1)的元素的话,那么使用min()和max()函数会更快些。
|
||||
类似的,如果N的大小和集合大小接近的时候,通常先排序这个集合然后再使用切片操作会更快点
|
||||
(sorted(items)[:N] 或者是 sorted(items)[-N:])。
|
||||
( ``sorted(items)[:N]`` 或者是 ``sorted(items)[-N:]`` )。
|
||||
需要在正确场合使用函数nlargest() 和 nsmallest()才能发挥它们的优势
|
||||
(如果N快接近集合大小了,那么使用排序操作会更好些)。
|
||||
|
||||
尽管你没有必要一定使用这里的方法,但是堆数据结构的实现是一个很有趣并且值得你深入学习的东西。
|
||||
基本上只要是数据结构和算法书籍里面都会有提及到。
|
||||
heapq模块的官方文档里面也详细的介绍了堆数据结构底层的实现细节。
|
||||
``heapq`` 模块的官方文档里面也详细的介绍了堆数据结构底层的实现细节。
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
----------
|
||||
解决方案
|
||||
----------
|
||||
下面的类利用heapq模块实现了一个简单的优先级队列:
|
||||
下面的类利用 ``heapq`` 模块实现了一个简单的优先级队列:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -56,27 +56,27 @@
|
||||
Item('grok')
|
||||
>>>
|
||||
|
||||
仔细观察可以发现,第一个pop()操作返回优先级最高的元素。
|
||||
另外注意到如果两个有着相同优先级的元素(foo 和 grok),pop操作按照它们被插入到队列的顺序返回的。
|
||||
仔细观察可以发现,第一个 ``pop()`` 操作返回优先级最高的元素。
|
||||
另外注意到如果两个有着相同优先级的元素( ``foo`` 和 ``grok`` ),pop操作按照它们被插入到队列的顺序返回的。
|
||||
|
||||
|
|
||||
|
||||
----------
|
||||
讨论
|
||||
----------
|
||||
这一小节我们主要关注heapq模块的使用。
|
||||
函数 ``heapq.heappush()`` 和 ``heapq.heappop()`` 分别在队列_queue上插入和删除第一个元素,
|
||||
这一小节我们主要关注 ``heapq`` 模块的使用。
|
||||
函数 ``heapq.heappush()`` 和 ``heapq.heappop()`` 分别在队列 ``_queue`` 上插入和删除第一个元素,
|
||||
并且队列_queue保证第一个元素拥有最小优先级(1.4节已经讨论过这个问题)。
|
||||
heappop()函数总是返回"最小的"的元素,这就是保证队列pop操作返回正确元素的关键。
|
||||
``heappop()`` 函数总是返回"最小的"的元素,这就是保证队列pop操作返回正确元素的关键。
|
||||
另外,由于push和pop操作时间复杂度为O(N),其中N是堆的大小,因此就算是N很大的时候它们运行速度也依旧很快。
|
||||
|
||||
在上面代码中,队列包含了一个 ``(-priority, index, item)`` 的元组。
|
||||
优先级为负数的目的是使得元素按照优先级从高到低排序。
|
||||
这个跟普通的按优先级从低到高排序的堆排序恰巧相反。
|
||||
|
||||
index变量的作用是保证同等优先级元素的正确排序。
|
||||
通过保存一个不断增加的index下标变量,可以确保元素安装它们插入的顺序排序。
|
||||
而且,index变量也在相同优先级元素比较的时候起到重要作用。
|
||||
``index`` 变量的作用是保证同等优先级元素的正确排序。
|
||||
通过保存一个不断增加的 ``index`` 下标变量,可以确保元素安装它们插入的顺序排序。
|
||||
而且, ``index`` 变量也在相同优先级元素比较的时候起到重要作用。
|
||||
|
||||
为了阐明这些,先假定Item实例是不支持排序的:
|
||||
|
||||
@@ -106,8 +106,8 @@ index变量的作用是保证同等优先级元素的正确排序。
|
||||
TypeError: unorderable types: Item() < Item()
|
||||
>>>
|
||||
|
||||
通过引入另外的index变量组成三元组(priority, index, item),就能很好的避免上面的错误,
|
||||
因为不可能有两个元素有相同的index值。Python在做元组比较时候,如果前面的比较以及可以确定结果了,
|
||||
通过引入另外的 ``index`` 变量组成三元组 ``(priority, index, item)`` ,就能很好的避免上面的错误,
|
||||
因为不可能有两个元素有相同的 ``index`` 值。Python在做元组比较时候,如果前面的比较以及可以确定结果了,
|
||||
后面的比较操作就不会发生了:
|
||||
|
||||
.. code-block:: python
|
||||
@@ -124,5 +124,5 @@ index变量的作用是保证同等优先级元素的正确排序。
|
||||
如果你想在多个线程中使用同一个队列,那么你需要增加适当的锁和信号量机制。
|
||||
可以查看12.3小节的例子演示是怎样做的。
|
||||
|
||||
heapq模块的官方文档有更详细的例子程序以及对于堆理论及其实现的详细说明。
|
||||
``heapq`` 模块的官方文档有更详细的例子程序以及对于堆理论及其实现的详细说明。
|
||||
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
选择使用列表还是集合取决于你的实际需求。如果你想保持元素的插入顺序就应该使用列表,
|
||||
如果想去掉重复元素就使用集合(并且不关心元素的顺序问题)。
|
||||
|
||||
你可以很方便的使用collections模块中的defaultdict来构造这样的字典。
|
||||
defaultdict的一个特征是它会自动初始化每个key刚开始对应的值,所以你只需要关注添加元素操作了。比如:
|
||||
你可以很方便的使用 ``collections`` 模块中的 ``defaultdict`` 来构造这样的字典。
|
||||
``defaultdict`` 的一个特征是它会自动初始化每个 ``key`` 刚开始对应的值,所以你只需要关注添加元素操作了。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -46,8 +46,8 @@ defaultdict的一个特征是它会自动初始化每个key刚开始对应的值
|
||||
d['a'].add(2)
|
||||
d['b'].add(4)
|
||||
|
||||
需要注意的是,defaultdict会自动为将要访问的键(就算目前字典中并不存在这样的键)创建映射实体。
|
||||
如果你并不需要这样的特性,你可以在一个普通的字典上使用setdefault()方法来代替。比如:
|
||||
需要注意的是, ``defaultdict`` 会自动为将要访问的键(就算目前字典中并不存在这样的键)创建映射实体。
|
||||
如果你并不需要这样的特性,你可以在一个普通的字典上使用 ``setdefault()`` 方法来代替。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -56,7 +56,7 @@ defaultdict的一个特征是它会自动初始化每个key刚开始对应的值
|
||||
d.setdefault('a', []).append(2)
|
||||
d.setdefault('b', []).append(4)
|
||||
|
||||
但是很多程序员觉得setdefault()用起来有点别扭。因为每次调用都得创建一个新的初始值的实例(例子程序中的空列表[])。
|
||||
但是很多程序员觉得 ``setdefault()`` 用起来有点别扭。因为每次调用都得创建一个新的初始值的实例(例子程序中的空列表[])。
|
||||
|
||||
|
|
||||
|
||||
@@ -74,7 +74,7 @@ defaultdict的一个特征是它会自动初始化每个key刚开始对应的值
|
||||
d[key] = []
|
||||
d[key].append(value)
|
||||
|
||||
如果使用defaultdict的话代码就更加简洁了:
|
||||
如果使用 ``defaultdict`` 的话代码就更加简洁了:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
----------
|
||||
解决方案
|
||||
----------
|
||||
为了能控制一个字典中元素的顺序,你可以使用collections模块中的OrderedDict类。
|
||||
为了能控制一个字典中元素的顺序,你可以使用 ``collections`` 模块中的 ``OrderedDict`` 类。
|
||||
在迭代操作的时候它会保持元素被插入时的顺序,示例如下:
|
||||
|
||||
.. code-block:: python
|
||||
@@ -28,8 +28,8 @@
|
||||
for key in d:
|
||||
print(key, d[key])
|
||||
|
||||
当你想要构建一个将来需要序列化或编码成其他格式的映射的时候,OrderedDict是非常有用的。
|
||||
比如,你想精确控制以JSON编码后字段的顺序,你可以先使用OrderedDict来构建这样的数据:
|
||||
当你想要构建一个将来需要序列化或编码成其他格式的映射的时候, ``OrderedDict`` 是非常有用的。
|
||||
比如,你想精确控制以JSON编码后字段的顺序,你可以先使用 ``OrderedDict`` 来构建这样的数据:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -43,9 +43,9 @@
|
||||
----------
|
||||
讨论
|
||||
----------
|
||||
OrderedDict内部维护着一个根据键插入顺序排序的双向链表。每次当一个新的元素插入进来的时候,
|
||||
``OrderedDict`` 内部维护着一个根据键插入顺序排序的双向链表。每次当一个新的元素插入进来的时候,
|
||||
它会被放到链表的尾部。对于一个已经存在的键的重复赋值不会改变键的顺序。
|
||||
|
||||
需要注意的是,一个OrderedDict的大小是一个普通字典的两倍,因为它内部维护着另外一个链表。
|
||||
所以如果你要构建一个需要大量OrderedDict实例的数据结构的时候(比如读取100,000行CSV数据到一个OrderedDict列表中去),
|
||||
那么你就得仔细权衡一下是否使用OrderedDict带来的好处要大过额外内存消耗的影响。
|
||||
需要注意的是,一个 ``OrderedDict`` 的大小是一个普通字典的两倍,因为它内部维护着另外一个链表。
|
||||
所以如果你要构建一个需要大量 ``OrderedDict`` 实例的数据结构的时候(比如读取100,000行CSV数据到一个 ``OrderedDict`` 列表中去),
|
||||
那么你就得仔细权衡一下是否使用 ``OrderedDict`` 带来的好处要大过额外内存消耗的影响。
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
'FB': 10.75
|
||||
}
|
||||
|
||||
为了对字典值执行计算操作,通常需要使用zip()函数先将键和值反转过来。
|
||||
为了对字典值执行计算操作,通常需要使用 ``zip()`` 函数先将键和值反转过来。
|
||||
比如,下面是查找最小和最大股票价格和股票值的代码:
|
||||
|
||||
.. code-block:: python
|
||||
@@ -34,7 +34,7 @@
|
||||
max_price = max(zip(prices.values(), prices.keys()))
|
||||
# max_price is (612.78, 'AAPL')
|
||||
|
||||
类似的,可以使用zip()和sorted()函数来排列字典数据:
|
||||
类似的,可以使用 ``zip()`` 和 ``sorted()`` 函数来排列字典数据:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
# (45.23, 'ACME'), (205.55, 'IBM'),
|
||||
# (612.78, 'AAPL')]
|
||||
|
||||
执行这些计算的时候,需要注意的是zip()函数创建的是一个只能访问一次的迭代器。
|
||||
执行这些计算的时候,需要注意的是 ``zip()`` 函数创建的是一个只能访问一次的迭代器。
|
||||
比如,下面的代码就会产生错误:
|
||||
|
||||
.. code-block:: python
|
||||
@@ -65,7 +65,7 @@
|
||||
max(prices) # Returns 'IBM'
|
||||
|
||||
这个结果并不是你想要的,因为你想要在字典的值集合上执行这些计算。
|
||||
或许你会尝试着使用字典的values()方法来解决这个问题:
|
||||
或许你会尝试着使用字典的 ``values()`` 方法来解决这个问题:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
不幸的是,通常这个结果同样也不是你想要的。
|
||||
你可能还想要知道对应的键的信息(比如那种股票价格是最低的?)。
|
||||
|
||||
你可以在min()和max()函数中提供key函数参数来获取最小值或最大值对应的键的信息。比如:
|
||||
你可以在 ``min()`` 和 ``max()`` 函数中提供 ``key`` 函数参数来获取最小值或最大值对应的键的信息。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -88,12 +88,12 @@
|
||||
|
||||
min_value = prices[min(prices, key=lambda k: prices[k])]
|
||||
|
||||
前面的zip()函数方案通过将字典"反转"为(值,键)元组序列来解决了上述问题。
|
||||
前面的 ``zip()`` 函数方案通过将字典"反转"为(值,键)元组序列来解决了上述问题。
|
||||
当比较两个元组的时候,值会先进行比较,然后才是键。
|
||||
这样的话你就能通过一条简单的语句就能很轻松的实现在字典上的求最值和排序操作了。
|
||||
|
||||
需要注意的是在计算操作中使用到了(值,键)对。当多个实体拥有相同的值的时候,键会决定返回结果。
|
||||
比如,在执行min()和max()操作的时候,如果恰巧最小或最大值有重复的,那么拥有最小或最大键的实体会返回:
|
||||
比如,在执行 ``min()`` 和 ``max()`` 操作的时候,如果恰巧最小或最大值有重复的,那么拥有最小或最大键的实体会返回:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
'y' : 2
|
||||
}
|
||||
|
||||
为了寻找两个字典的相同点,可以简单的在两字典的keys()或者items()方法返回结果上执行集合操作。比如:
|
||||
为了寻找两个字典的相同点,可以简单的在两字典的 ``keys()`` 或者 ``items()`` 方法返回结果上执行集合操作。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -55,14 +55,14 @@
|
||||
讨论
|
||||
----------
|
||||
一个字典就是一个键集合与值集合的映射关系。
|
||||
字典的keys()方法返回一个展现键集合的键视图对象。
|
||||
字典的 ``keys()`` 方法返回一个展现键集合的键视图对象。
|
||||
键视图的一个很少被了解的特性就是它们也支持集合操作,比如集合并、交、差运算。
|
||||
所以,如果你想对集合的键执行一些普通的集合操作,可以直接使用键视图对象而不用先将它们转换成一个set。
|
||||
|
||||
字典的items()方法返回一个包含(键,值)对的元素视图对象。
|
||||
字典的 ``items()`` 方法返回一个包含(键,值)对的元素视图对象。
|
||||
这个对象同样也支持集合操作,并且可以被用来查找两个字典有哪些相同的键值对。
|
||||
|
||||
尽管字典的values()方法也是类似,但是它并不支持这里介绍的集合操作。
|
||||
尽管字典的 ``values()`` 方法也是类似,但是它并不支持这里介绍的集合操作。
|
||||
某种程度上是因为值视图不能保证所有的值互不相同,这样会导致某些集合操作会出现问题。
|
||||
不过,如果你硬要在值上面执行这些集合操作的话,你可以先将值集合转换成set,然后再执行集合运算就行了。
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
----------
|
||||
解决方案
|
||||
----------
|
||||
如果序列上的值都是hashable类型,那么可以很简单的利用集合或者生成器来解决这个问题。比如:
|
||||
如果序列上的值都是 ``hashable`` 类型,那么可以很简单的利用集合或者生成器来解决这个问题。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
>>> list(dedupe(a))
|
||||
[1, 5, 2, 9, 10]
|
||||
>>>
|
||||
这个方法仅仅在序列中元素为hashable的时候才管用。
|
||||
如果你想消除元素不可哈希(比如dict类型)的序列中重复元素的话,你需要将上述代码稍微改变一下,就像这样:
|
||||
这个方法仅仅在序列中元素为 ``hashable`` 的时候才管用。
|
||||
如果你想消除元素不可哈希(比如 ``dict`` 类型)的序列中重复元素的话,你需要将上述代码稍微改变一下,就像这样:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
yield item
|
||||
seen.add(val)
|
||||
|
||||
这里的key参数指定了一个函数,将序列元素转换成hashable类型。下面是它的用法示例:
|
||||
这里的key参数指定了一个函数,将序列元素转换成 ``hashable`` 类型。下面是它的用法示例:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -82,5 +82,5 @@
|
||||
for line in dedupe(f):
|
||||
...
|
||||
|
||||
上述key函数参数模仿了sorted(),min()和max()等内置函数的相似功能。
|
||||
上述key函数参数模仿了 ``sorted()`` , ``min()`` 和 ``max()`` 等内置函数的相似功能。
|
||||
可以参考1.8和1.13小节了解更多。
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
比如,如果你回过来看看一年前你写的代码,你会摸着脑袋想那时候自己到底想干嘛啊。
|
||||
这里的解决方案是一个很简单的方法让你更加清晰的表达代码到底要做什么。
|
||||
|
||||
内置的slice()函数创建了一个切片对象,可以被用在任何切片允许使用的地方。比如:
|
||||
内置的 ``slice()`` 函数创建了一个切片对象,可以被用在任何切片允许使用的地方。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
>>> items
|
||||
[0, 1, 4, 5, 6]
|
||||
|
||||
如果你有一个切片对象s,你可以分别调用它的s.start, s.stop, s.step属性来获取更多的信息。比如:
|
||||
如果你有一个切片对象s,你可以分别调用它的 ``s.start`` , ``s.stop`` , ``s.step`` 属性来获取更多的信息。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -69,9 +69,9 @@
|
||||
2
|
||||
>>>
|
||||
|
||||
另外,你还能通过调用切片的indices(size)方法将它映射到一个确定大小的序列上,
|
||||
这个方法返回一个三元组(start,stop,step),所有值都会被合适的缩小以满足边界限制,
|
||||
从而使用的时候避免出现IndexError异常。比如:
|
||||
另外,你还能通过调用切片的 ``indices(size)`` 方法将它映射到一个确定大小的序列上,
|
||||
这个方法返回一个三元组 ``(start, stop, step)`` ,所有值都会被合适的缩小以满足边界限制,
|
||||
从而使用的时候避免出现 ``IndexError`` 异常。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
----------
|
||||
讨论
|
||||
----------
|
||||
作为输入,``Counter`` 对象可以接受任意的 ``hashable`` 序列对象。
|
||||
作为输入, ``Counter`` 对象可以接受任意的 ``hashable`` 序列对象。
|
||||
在底层实现上,一个 ``Counter`` 对象就是一个字典,将元素映射到它出现的次数上。比如:
|
||||
|
||||
.. code-block:: python
|
||||
@@ -60,7 +60,7 @@
|
||||
9
|
||||
>>>
|
||||
|
||||
或者你可以使用update()方法:
|
||||
或者你可以使用 ``update()`` 方法:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -92,6 +92,6 @@
|
||||
"you're": 1, "don't": 1, 'under': 1})
|
||||
>>>
|
||||
|
||||
毫无疑问,``Counter`` 对象在几乎所有需要制表或者计数数据的场合是非常有用的工具。
|
||||
毫无疑问, ``Counter`` 对象在几乎所有需要制表或者计数数据的场合是非常有用的工具。
|
||||
在解决这类问题的时候你应该优先选择它,而不是手动的利用字典去实现。
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
----------
|
||||
解决方案
|
||||
----------
|
||||
通过使用operator模块的itemgetter函数,可以非常容易的排序这样的数据结构。
|
||||
通过使用 ``operator`` 模块的 ``itemgetter`` 函数,可以非常容易的排序这样的数据结构。
|
||||
假设你从数据库中检索出来网站会员信息列表,并且以下列的数据结构返回:
|
||||
|
||||
.. code-block:: python
|
||||
@@ -47,7 +47,7 @@
|
||||
{'fname': 'Brian', 'uid': 1003, 'lname': 'Jones'},
|
||||
{'fname': 'Big', 'uid': 1004, 'lname': 'Jones'}]
|
||||
|
||||
itemgetter()函数也支持多个keys,比如下面的代码
|
||||
``itemgetter()`` 函数也支持多个keys,比如下面的代码
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -68,26 +68,26 @@ itemgetter()函数也支持多个keys,比如下面的代码
|
||||
----------
|
||||
讨论
|
||||
----------
|
||||
在上面例子中,``rows`` 被传递给接受一个关键字参数的 ``sorted()`` 内置函数。
|
||||
在上面例子中, ``rows`` 被传递给接受一个关键字参数的 ``sorted()`` 内置函数。
|
||||
这个参数是 ``callable`` 类型,并且从 ``rows`` 中接受一个单一元素,然后返回被用来排序的值。
|
||||
``itemgetter()`` 函数就是负责创建这个 ``callable`` 对象的。
|
||||
|
||||
``operator.itemgetter()`` 函数有一个被rows中的记录用来查找值的索引参数。可以是一个字典键名称,
|
||||
一个整形值或者任何能够传入一个对象的 ``__getitem__()`` 方法的值。
|
||||
如果你传入多个索引参数给 ``itemgetter()`` ,它生成的 ``callable`` 对象会返回一个包含所有元素值的元组,
|
||||
并且sorted()函数会根据这个元组中元素顺序去排序。
|
||||
并且 ``sorted()`` 函数会根据这个元组中元素顺序去排序。
|
||||
但你想要同时在几个字段上面进行排序(比如通过姓和名来排序,也就是例子中的那样)的时候这种方法是很有用的。
|
||||
|
||||
``itemgetter()`` 有时候也可以用lambda表达式代替,比如:
|
||||
``itemgetter()`` 有时候也可以用 ``lambda`` 表达式代替,比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
rows_by_fname = sorted(rows, key=lambda r: r['fname'])
|
||||
rows_by_lfname = sorted(rows, key=lambda r: (r['lname'],r['fname']))
|
||||
|
||||
这种方案也不错。但是,使用itemgetter()方式会运行的稍微快点。因此,如果你对性能要求比较高的话就使用itemgetter()方式。
|
||||
这种方案也不错。但是,使用 ``itemgetter()`` 方式会运行的稍微快点。因此,如果你对性能要求比较高的话就使用 ``itemgetter()`` 方式。
|
||||
|
||||
最后,不要忘了这节中展示的技术也同样适用于min()和max()等函数。比如:
|
||||
最后,不要忘了这节中展示的技术也同样适用于 ``min()`` 和 ``max()`` 等函数。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
----------
|
||||
内置的 ``sorted()`` 函数有一个关键字参数 ``key`` ,可以传入一个 ``callable`` 对象给它,
|
||||
这个 ``callable`` 对象对每个传入的对象返回一个值,这个值会被 ``sorted`` 用来排序这些对象。
|
||||
比如,如果你在应用程序里面有一个User实例序列,并且你希望通过他们的user_id属性进行排序,
|
||||
你可以提供一个以User实例作为输入并输出对应user_id值的 ``callable`` 对象。比如:
|
||||
比如,如果你在应用程序里面有一个 ``User`` 实例序列,并且你希望通过他们的 ``user_id`` 属性进行排序,
|
||||
你可以提供一个以 ``User`` 实例作为输入并输出对应 ``user_id`` 值的 ``callable`` 对象。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -47,9 +47,9 @@
|
||||
讨论
|
||||
----------
|
||||
选择使用lambda函数或者是 ``attrgetter()`` 可能取决于个人喜好。
|
||||
但是,``attrgetter()`` 函数通常会运行的快点,并且还能同时允许多个字段进行比较。
|
||||
但是, ``attrgetter()`` 函数通常会运行的快点,并且还能同时允许多个字段进行比较。
|
||||
这个跟 ``operator.itemgetter()`` 函数作用于字典类型很类似(参考1.13小节)。
|
||||
例如,如果User实例还有一个first_name和last_name属性,那么可以向下面这样排序:
|
||||
例如,如果 ``User`` 实例还有一个 ``first_name`` 和 ``last_name`` 属性,那么可以向下面这样排序:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
----------
|
||||
问题
|
||||
----------
|
||||
你有一个字典或者实例的序列,然后你想根据某个特定的字段比如date来分组迭代访问。
|
||||
你有一个字典或者实例的序列,然后你想根据某个特定的字段比如 ``date`` 来分组迭代访问。
|
||||
|
||||
|
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
{'address': '1039 W GRANVILLE', 'date': '07/04/2012'},
|
||||
]
|
||||
|
||||
现在假设你想在按date分组后的数据块上进行迭代。为了这样做,你首先需要按照指定的字段(这里就是date)排序,
|
||||
现在假设你想在按date分组后的数据块上进行迭代。为了这样做,你首先需要按照指定的字段(这里就是 ``date`` )排序,
|
||||
然后调用 ``itertools.groupby()`` 函数:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -87,8 +87,8 @@
|
||||
[0, 0, -5, 0, -7, 0, 0, -1]
|
||||
>>>
|
||||
另外一个值得关注的过滤工具就是 ``itertools.compress()`` ,
|
||||
它以一个 ``iterable`` 对象和一个相对应的Boolean选择器序列作为输入参数。
|
||||
然后输出 ``iterable`` 对象中对应选择器为True的元素。
|
||||
它以一个 ``iterable`` 对象和一个相对应的 ``Boolean`` 选择器序列作为输入参数。
|
||||
然后输出 ``iterable`` 对象中对应选择器为 ``True`` 的元素。
|
||||
当你需要用另外一个相关联的序列来过滤某个序列的时候,这个函数是非常有用的。
|
||||
比如,假如现在你有下面两列数据:
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
]
|
||||
counts = [ 0, 3, 10, 4, 1, 7, 6, 1]
|
||||
|
||||
现在你想将那些对应count值大于5的地址全部输出,那么你可以这样做:
|
||||
现在你想将那些对应 ``count`` 值大于5的地址全部输出,那么你可以这样做:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -117,8 +117,8 @@
|
||||
>>> list(compress(addresses, more5))
|
||||
['5800 E 58TH', '4801 N BROADWAY', '1039 W GRANVILLE']
|
||||
>>>
|
||||
这里的关键点在于先创建一个Boolean序列,指示哪些元素复合条件。
|
||||
然后 ``compress()`` 函数根据这个序列去选择输出对应位置为True的元素。
|
||||
这里的关键点在于先创建一个 ``Boolean`` 序列,指示哪些元素复合条件。
|
||||
然后 ``compress()`` 函数根据这个序列去选择输出对应位置为 ``True`` 的元素。
|
||||
|
||||
和 ``filter()`` 函数类似,``compress()`` 也是返回的一个迭代器。因此,如果你需要得到一个列表,
|
||||
和 ``filter()`` 函数类似, ``compress()`` 也是返回的一个迭代器。因此,如果你需要得到一个列表,
|
||||
那么你需要使用 ``list()`` 来将结果转换为列表类型。
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
'2012-10-19'
|
||||
>>>
|
||||
|
||||
尽管namedtuple的实例看起来像一个普通的类实例,但是它跟元组类型是可交换的,支持所有的普通元组操作,比如索引和解压。
|
||||
尽管 ``namedtuple`` 的实例看起来像一个普通的类实例,但是它跟元组类型是可交换的,支持所有的普通元组操作,比如索引和解压。
|
||||
比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
a = {'x': 1, 'z': 3 }
|
||||
b = {'y': 2, 'z': 4 }
|
||||
|
||||
现在假设你必须在两个字典中执行查找操作(比如先从a中找,如果找不到再在b中找)。
|
||||
一个非常简单扼解决方案就是使用collections模块中的ChainMap类。比如:
|
||||
现在假设你必须在两个字典中执行查找操作(比如先从 ``a`` 中找,如果找不到再在 ``b`` 中找)。
|
||||
一个非常简单扼解决方案就是使用 ``collections`` 模块中的 ``ChainMap`` 类。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -36,8 +36,8 @@
|
||||
----------
|
||||
讨论
|
||||
----------
|
||||
一个ChainMap接受多个字典并将它们在逻辑上变为一个字典。
|
||||
然后,这些字典并不是真的合并在一起了,ChainMap类只是在内部创建了一个容纳这些字典的列表
|
||||
一个 ``ChainMap`` 接受多个字典并将它们在逻辑上变为一个字典。
|
||||
然后,这些字典并不是真的合并在一起了, ``ChainMap`` 类只是在内部创建了一个容纳这些字典的列表
|
||||
并重新定义了一些常见的字典操作来遍历这个列表。大部分字典操作都是可以正常使用的,比如:
|
||||
|
||||
.. code-block:: python
|
||||
@@ -51,7 +51,7 @@
|
||||
>>>
|
||||
|
||||
如果出现重复键,那么第一次出现的映射值会被返回。
|
||||
因此,例子程序中的c['z']总是会返回字典a中对应的值,而不是b中对应的值。
|
||||
因此,例子程序中的 ``c['z']`` 总是会返回字典 ``a`` 中对应的值,而不是 ``b`` 中对应的值。
|
||||
|
||||
对于字典的更新或删除操作总是影响的是列表中第一个字典。比如:
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
KeyError: "Key not found in the first mapping: 'y'"
|
||||
>>>
|
||||
|
||||
ChainMap对于编程语言中的作用范围变量(比如globals, locals等)是非常有用的。
|
||||
``ChainMap`` 对于编程语言中的作用范围变量(比如 ``globals`` , ``locals`` 等)是非常有用的。
|
||||
事实上,有一些方法可以使它变得简单:
|
||||
|
||||
.. code-block:: python
|
||||
@@ -97,7 +97,7 @@ ChainMap对于编程语言中的作用范围变量(比如globals, locals等)是
|
||||
ChainMap({'x': 1})
|
||||
>>>
|
||||
|
||||
作为ChainMap的替代,你可能会考虑使用update()方法将两个字典合并。比如:
|
||||
作为 ``ChainMap`` 的替代,你可能会考虑使用 ``update()`` 方法将两个字典合并。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -122,7 +122,7 @@ ChainMap对于编程语言中的作用范围变量(比如globals, locals等)是
|
||||
>>> merged['x']
|
||||
1
|
||||
|
||||
ChianMap使用原来的字典,它自己不创建新的字典。所以它并不会产生上面所说的结果,比如:
|
||||
``ChianMap`` 使用原来的字典,它自己不创建新的字典。所以它并不会产生上面所说的结果,比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
----------
|
||||
解决方案
|
||||
----------
|
||||
string对象的 ``split()`` 方法只适应于非常简单的字符串分割情形,
|
||||
``string`` 对象的 ``split()`` 方法只适应于非常简单的字符串分割情形,
|
||||
它并不允许有多个分隔符或者是分隔符周围不确定的空格。
|
||||
当你需要更加灵活的切割字符串的时候,最好使用 ``re.split()`` 方法:
|
||||
|
||||
@@ -29,7 +29,7 @@ string对象的 ``split()`` 方法只适应于非常简单的字符串分割情
|
||||
讨论
|
||||
----------
|
||||
函数 ``re.split()`` 是非常实用的,因为它允许你为分隔符指定多个正则模式。
|
||||
比如,在上面的例子中,分隔符可以是逗号(,),分号(;)或者是空格,并且后面紧跟着任意个的空格。
|
||||
比如,在上面的例子中,分隔符可以是逗号,分号或者是空格,并且后面紧跟着任意个的空格。
|
||||
只要这个模式被找到,那么匹配的分隔符两边的实体都会被当成是结果中的元素返回。
|
||||
返回结果为一个字段列表,这个跟 ``str.split()`` 返回值类型是一样的。
|
||||
|
||||
@@ -60,7 +60,7 @@ string对象的 ``split()`` 方法只适应于非常简单的字符串分割情
|
||||
>>>
|
||||
|
||||
如果你不想保留分割字符串到结果列表中去,但仍然需要使用到括号来分组正则表达式的话,
|
||||
确保你的分组是非捕获分组,形如(?:...)。比如:
|
||||
确保你的分组是非捕获分组,形如 ``(?:...)`` 。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
----------
|
||||
问题
|
||||
----------
|
||||
你想使用Unix Shell中常用的通配符(比如*.py, Dat[0-9]*.csv等)去匹配文本字符串
|
||||
你想使用 **Unix Shell** 中常用的通配符(比如 ``*.py`` , ``Dat[0-9]*.csv`` 等)去匹配文本字符串
|
||||
|
||||
|
|
||||
|
||||
----------
|
||||
解决方案
|
||||
----------
|
||||
fnmatch模块提供了两个函数—— ``fnmatch()`` 和 ``fnmatchcase()`` ,可以用来实现这样的匹配。用法如下:
|
||||
``fnmatch`` 模块提供了两个函数—— ``fnmatch()`` 和 ``fnmatchcase()`` ,可以用来实现这样的匹配。用法如下:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -42,7 +42,7 @@ fnmatch模块提供了两个函数—— ``fnmatch()`` 和 ``fnmatchcase()`` ,
|
||||
|
||||
如果你对这个区别很在意,可以使用 ``fnmatchcase()`` 来代替。它完全使用你的模式大小写匹配。比如:
|
||||
|
||||
.. code-block:: python
|
||||
.. code-block:: python
|
||||
|
||||
>>> fnmatchcase('foo.txt', '*.TXT')
|
||||
False
|
||||
@@ -80,5 +80,5 @@ fnmatch模块提供了两个函数—— ``fnmatch()`` 和 ``fnmatchcase()`` ,
|
||||
``fnmatch()`` 函数匹配能力介于简单的字符串方法和强大的正则表达式之间。
|
||||
如果在数据处理操作中只需要简单的通配符就能完成的时候,这通常是一个比较合理的方案。
|
||||
|
||||
如果你的代码需要做文件名的匹配,最好使用glob模块。参考5.13小节。
|
||||
如果你的代码需要做文件名的匹配,最好使用 ``glob`` 模块。参考5.13小节。
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
10
|
||||
>>>
|
||||
|
||||
对于复杂的匹配需要使用正则表达式和re模块。
|
||||
为了解释正则表达式的基本原理,假设你想匹配数字格式的日期字符串比如"11/27/2012",你可以这样做:
|
||||
对于复杂的匹配需要使用正则表达式和 ``re`` 模块。
|
||||
为了解释正则表达式的基本原理,假设你想匹配数字格式的日期字符串比如 ``11/27/2012`` ,你可以这样做:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -170,7 +170,7 @@
|
||||
<_sre.SRE_Match object at 0x1005d2750>
|
||||
>>>
|
||||
|
||||
最后,如果你仅仅是做一次简单的文本匹配/搜索操作的话,可以略过编译部分,直接使用re模块级别的函数。比如:
|
||||
最后,如果你仅仅是做一次简单的文本匹配/搜索操作的话,可以略过编译部分,直接使用 ``re`` 模块级别的函数。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
'yep, but no, but yep, but no, but yep'
|
||||
>>>
|
||||
|
||||
对于复杂的模式,请使用re模块中的 ``sub()`` 函数。
|
||||
为了说明这个,假设你想将形式为"11/27/201"的日期字符串改成"2012-11-27"。示例如下:
|
||||
对于复杂的模式,请使用 ``re`` 模块中的 ``sub()`` 函数。
|
||||
为了说明这个,假设你想将形式为 ``11/27/201`` 的日期字符串改成 ``2012-11-27`` 。示例如下:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
'Today is 2012-11-27. PyCon starts 2013-3-13.'
|
||||
>>>
|
||||
|
||||
``sub()`` 函数中的第一个参数是被匹配的模式,第二个参数是替换模式。反斜杠数字比如\3指向前面模式的捕获组号。
|
||||
``sub()`` 函数中的第一个参数是被匹配的模式,第二个参数是替换模式。反斜杠数字比如 ``\3`` 指向前面模式的捕获组号。
|
||||
|
||||
如果你打算用相同的模式做多次替换,考虑先编译它来提升性能。比如:
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
----------
|
||||
解决方案
|
||||
----------
|
||||
为了在文本操作时忽略大小写,你需要在使用re模块的时候给这些操作提供 ``re.IGNORECASE`` 标志参数。比如:
|
||||
为了在文本操作时忽略大小写,你需要在使用 ``re`` 模块的时候给这些操作提供 ``re.IGNORECASE`` 标志参数。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
@@ -51,5 +51,5 @@
|
||||
在一个模式字符串中,点(.)匹配除了换行外的任何字符。
|
||||
然而,如果你将点(.)号放在开始与结束符(比如引号)之间的时候,那么匹配操作会查找符合模式的最长可能匹配。
|
||||
这样通常会导致很多中间的被开始与结束符包含的文本被忽略掉,并最终被包含在匹配结果字符串中返回。
|
||||
通过在*或者+这样的操作符后面添加一个?可以强制匹配算法改成寻找最短的可能匹配。
|
||||
通过在 ``*`` 或者 ``+`` 这样的操作符后面添加一个 ``?`` 可以强制匹配算法改成寻找最短的可能匹配。
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
[' this is a\n multiline comment ']
|
||||
>>>
|
||||
|
||||
在这个模式中,``(?:.|\n)`` 指定了一个非捕获组
|
||||
在这个模式中, ``(?:.|\n)`` 指定了一个非捕获组
|
||||
(也就是它定义了一个仅仅用来做匹配,而不能通过单独捕获或者编号的组)。
|
||||
|
||||
|
|
||||
@@ -47,7 +47,7 @@
|
||||
讨论
|
||||
----------
|
||||
``re.compile()`` 函数接受一个标志参数叫 ``re.DOTALL`` ,在这里非常有用。
|
||||
它可以让正则表达式中的.匹配包括换行符在内的任意字符。比如:
|
||||
它可以让正则表达式中的点(.)匹配包括换行符在内的任意字符。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
----------
|
||||
解决方案
|
||||
----------
|
||||
默认情况下re模块已经对一些Unicode字符类有了基本的支持。
|
||||
比如,\\d已经匹配任意的unicode数字字符了:
|
||||
默认情况下 ``re`` 模块已经对一些Unicode字符类有了基本的支持。
|
||||
比如, ``\\d`` 已经匹配任意的unicode数字字符了:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<_sre.SRE_Match object at 0x101234030>
|
||||
>>>
|
||||
|
||||
如果你想在模式中包含指定的Unicode字符,你可以使用Unicode字符对应的转义序列(比如\uFFF或者\UFFFFFFF)。
|
||||
如果你想在模式中包含指定的Unicode字符,你可以使用Unicode字符对应的转义序列(比如 ``\uFFF`` 或者 ``\UFFFFFFF`` )。
|
||||
比如,下面是一个匹配几个不同阿拉伯编码页面中所有字符的正则表达式:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
----------
|
||||
解决方案
|
||||
----------
|
||||
``strip()`` 方法能用于删除开始或结尾的字符。``lstrip()`` 和 ``rstrip()`` 分别从左和从右执行删除操作。
|
||||
``strip()`` 方法能用于删除开始或结尾的字符。 ``lstrip()`` 和 ``rstrip()`` 分别从左和从右执行删除操作。
|
||||
默认情况下,这些方法会去除空白字符,但是你也可以指定其他字符。比如:
|
||||
|
||||
.. code-block:: python
|
||||
@@ -63,7 +63,7 @@
|
||||
'hello world'
|
||||
>>>
|
||||
|
||||
通常情况下你想将字符串strip操作和其他迭代操作相结合,比如从文件中读取多行数据。
|
||||
通常情况下你想将字符串 ``strip`` 操作和其他迭代操作相结合,比如从文件中读取多行数据。
|
||||
如果是这样的话,那么生成器表达式就可以大显身手了。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
'pýtĥöñ is awesome\n'
|
||||
>>>
|
||||
|
||||
正如你看的那样,空白字符\t和\f已经被重新映射到一个空格。回车字符\r直接被删除。
|
||||
正如你看的那样,空白字符 ``\t`` 和 ``\f`` 已经被重新映射到一个空格。回车字符\r直接被删除。
|
||||
|
||||
你可以以这个表格为基础进一步构建更大的表格。比如,让我们删除所有的和音符:
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
'python is awesome\n'
|
||||
>>>
|
||||
|
||||
上面例子中,通过使用 ``dict.fromkeys()`` 方法构造一个字典,每个Unicode和音符作为键,对于的值全部为None。
|
||||
上面例子中,通过使用 ``dict.fromkeys()`` 方法构造一个字典,每个Unicode和音符作为键,对于的值全部为 ``None`` 。
|
||||
|
||||
然后使用 ``unicodedata.normalize()`` 将原始输入标准化为分解形式字符。
|
||||
然后再调用 ``translate`` 函数删除所有重音符。
|
||||
@@ -103,7 +103,7 @@
|
||||
讨论
|
||||
----------
|
||||
文本字符清理一个最主要的问题应该是运行的性能。一般来讲,代码越简单运行越快。
|
||||
对于简单的替换操作,``str.replace()`` 方法通常是最快的,甚至在你需要多次调用的时候。
|
||||
对于简单的替换操作, ``str.replace()`` 方法通常是最快的,甚至在你需要多次调用的时候。
|
||||
比如,为了清理空白字符,你可以这样做:
|
||||
|
||||
.. code-block:: python
|
||||
@@ -116,7 +116,7 @@
|
||||
|
||||
如果你去测试的话,你就会发现这种方式会比使用 ``translate()`` 或者正则表达式要快很多。
|
||||
|
||||
另一方面,如果你需要执行任何复杂字符对字符的重新映射或者删除操作的话,``tanslate()`` 方法会非常的快。
|
||||
另一方面,如果你需要执行任何复杂字符对字符的重新映射或者删除操作的话, ``tanslate()`` 方法会非常的快。
|
||||
|
||||
从大的方面来讲,对于你的应用程序来说性能是你不得不去自己研究的东西。
|
||||
不幸的是,我们不可能给你建议一个特定的技术,使它能够适应所有的情况。
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
>>>
|
||||
|
||||
函数 ``format()`` 同样可以用来很容易的对齐字符串。
|
||||
你要做的就是使用<,>或者^字符后面紧跟一个指定的宽度。比如:
|
||||
你要做的就是使用 ``<,>`` 或者 ``^`` 字符后面紧跟一个指定的宽度。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
----------
|
||||
讨论
|
||||
----------
|
||||
在老的代码中,你经常会看到被用来格式化文本的%操作符。比如:
|
||||
在老的代码中,你经常会看到被用来格式化文本的 ``%`` 操作符。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
>>>
|
||||
|
||||
但是,在新版本代码中,你应该优先选择 ``format()`` 函数或者方法。
|
||||
``format()`` 要比%操作符的功能更为强大。
|
||||
``format()`` 要比 ``%`` 操作符的功能更为强大。
|
||||
并且 ``format()`` 也比使用 ``ljust()`` , ``rjust()`` 或 ``center()`` 方法更通用,
|
||||
因为它可以用来格式化任意对象,而不仅仅是字符串。
|
||||
|
||||
|
||||
@@ -124,13 +124,13 @@ Python并没有对在字符串中简单替换变量值提供直接的支持。
|
||||
'Guido has 37 messages.'
|
||||
>>>
|
||||
|
||||
然而,``format()`` 和 ``format_map()`` 相比较上面这些方案而已更加先进,因此应该被优先选择。
|
||||
然而, ``format()`` 和 ``format_map()`` 相比较上面这些方案而已更加先进,因此应该被优先选择。
|
||||
使用 ``format()`` 方法还有一个好处就是你可以获得对字符串格式化的所有支持(对齐,填充,数字格式化等待),
|
||||
而这些特性是使用像模板字符串之类的方案不可能获得的。
|
||||
|
||||
本机还部分介绍了一些高级特性。映射或者字典类中鲜为人知的 ``__missing__()`` 方法可以让你定义如何处理缺失的值。
|
||||
在SafeSub类中,这个方法被定义为对缺失的值返回一个占位符。
|
||||
你可以发现缺失的值会出现在结果字符串中(在调试的时候可能很有用),而不是产生一个KeyError异常。
|
||||
在 ``SafeSub`` 类中,这个方法被定义为对缺失的值返回一个占位符。
|
||||
你可以发现缺失的值会出现在结果字符串中(在调试的时候可能很有用),而不是产生一个 ``KeyError`` 异常。
|
||||
|
||||
``sub()`` 函数使用 ``sys._getframe(1)`` 返回调用者的栈帧。可以从中访问属性 ``f_locals`` 来获得局部变量。
|
||||
毫无疑问绝大部分情况下在代码中去直接操作栈帧应该是不推荐的。
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
master_pat = re.compile('|'.join([NAME, NUM, PLUS, TIMES, EQ, WS]))
|
||||
|
||||
在上面的模式中,``?P<TOKENNAME>`` 用于给一个模式命名,供后面使用。
|
||||
在上面的模式中, ``?P<TOKENNAME>`` 用于给一个模式命名,供后面使用。
|
||||
|
||||
下一步,为了令牌化,使用模式对象很少被人知道的 ``scanner()`` 方法。
|
||||
这个方法会创建一个 ``scanner`` 对象,
|
||||
@@ -113,7 +113,7 @@
|
||||
第一点就是你必须确认你使用正则表达式指定了所有输入中可能出现的文本序列。
|
||||
如果有任何不可匹配的文本出现了,扫描就会直接停止。这也是为什么上面例子中必须指定空白字符令牌的原因。
|
||||
|
||||
令牌的顺序也是有影响的。re模块会按照指定好的顺序去做匹配。
|
||||
令牌的顺序也是有影响的。 ``re`` 模块会按照指定好的顺序去做匹配。
|
||||
因此,如果一个模式恰好是另一个更长模式的子字符串,那么你需要确定长模式写在前面。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
1.254
|
||||
>>>
|
||||
|
||||
当一个值刚好在两个边界的中间的时候,``round`` 函数返回离它最近的偶数。
|
||||
当一个值刚好在两个边界的中间的时候, ``round`` 函数返回离它最近的偶数。
|
||||
也就是说,对1.5或者2.5的舍入运算都会得到2。
|
||||
|
||||
传给 ``round()`` 函数的 ``ndigits`` 参数可以是负数,这种情况下,
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
这些错误是由底层CPU和IEEE 754标准通过自己的浮点单位去执行算术时的特征。
|
||||
由于Python的浮点数据类型使用底层表示存储数据,因此你没办法去避免这样的误差。
|
||||
|
||||
如果你想更加精确(并能容忍一定的性能损耗),你可以使用decimal模块:
|
||||
如果你想更加精确(并能容忍一定的性能损耗),你可以使用 ``decimal`` 模块:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -43,10 +43,10 @@
|
||||
True
|
||||
|
||||
初看起来,上面的代码好像有点奇怪,比如我们用字符串来表示数字。
|
||||
然而,Decimal对象会像普通浮点数一样的工作(支持所有的常用数学运算)。
|
||||
然而, ``Decimal`` 对象会像普通浮点数一样的工作(支持所有的常用数学运算)。
|
||||
如果你打印它们或者在字符串格式化函数中使用它们,看起来跟普通数字没什么两样。
|
||||
|
||||
decimal模块的一个主要特征是允许你控制计算的每一方面,包括数字位数和四舍五入运算。
|
||||
``decimal`` 模块的一个主要特征是允许你控制计算的每一方面,包括数字位数和四舍五入运算。
|
||||
为了这样做,你先得创建一个本地上下文并更改它的设置,比如:
|
||||
|
||||
.. code-block:: python
|
||||
@@ -73,9 +73,9 @@ decimal模块的一个主要特征是允许你控制计算的每一方面,包
|
||||
----------
|
||||
讨论
|
||||
----------
|
||||
decimal模块实现了IBM的"通用小数运算规范"。不用说,有很多的配置选项这本书没有提到。
|
||||
``decimal`` 模块实现了IBM的"通用小数运算规范"。不用说,有很多的配置选项这本书没有提到。
|
||||
|
||||
Python新手会倾向于使用decimal模块来处理浮点数的精确运算。
|
||||
Python新手会倾向于使用 ``decimal`` 模块来处理浮点数的精确运算。
|
||||
然而,先理解你的应用程序目的是非常重要的。
|
||||
如果你是在做科学计算或工程领域的计算、电脑绘图,或者是科学领域的大多数运算,
|
||||
那么使用普通的浮点类型是比较普遍的做法。
|
||||
@@ -104,7 +104,7 @@ Python新手会倾向于使用decimal模块来处理浮点数的精确运算。
|
||||
|
||||
然而,对于其他的算法,你应该仔细研究它并理解它的误差产生来源。
|
||||
|
||||
总的来说,decimal模块主要用在涉及到金融的领域。
|
||||
总的来说, ``decimal`` 模块主要用在涉及到金融的领域。
|
||||
在这类程序中,哪怕是一点小小的误差在计算过程中蔓延都是不允许的。
|
||||
因此,decimal模块为解决这类问题提供了方法。
|
||||
当Python和数据库打交道的时候也通常会遇到Decimal对象,并且,通常也是在处理金融数据的时候。
|
||||
因此, ``decimal`` 模块为解决这类问题提供了方法。
|
||||
当Python和数据库打交道的时候也通常会遇到 ``Decimal`` 对象,并且,通常也是在处理金融数据的时候。
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
----------
|
||||
讨论
|
||||
----------
|
||||
数字格式化输出通常是比较简单的。上面演示的技术同时适用于浮点数和decimal模块中的Decimal数字对象。
|
||||
数字格式化输出通常是比较简单的。上面演示的技术同时适用于浮点数和 ``decimal`` 模块中的 ``Decimal`` 数字对象。
|
||||
|
||||
当指定数字的位数后,结果值会根据 ``round()`` 函数同样的规则进行四舍五入后返回。比如:
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
>>>
|
||||
|
||||
包含千位符的格式化跟本地化没有关系。
|
||||
如果你需要根据地区来显示千位符,你需要自己去调查下locale模块中的函数了。
|
||||
如果你需要根据地区来显示千位符,你需要自己去调查下 ``locale`` 模块中的函数了。
|
||||
你同样也可以使用字符串的 ``translate()`` 方法来交换千位符。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
解决方案
|
||||
----------
|
||||
为了将整数转换为二进制、八进制或十六进制的文本串,
|
||||
可以分别使用 ``bin()`` 、``oct()`` 或 ``hex()`` 函数:
|
||||
可以分别使用 ``bin()`` , ``oct()`` 或 ``hex()`` 函数:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
'fffffb2e'
|
||||
>>>
|
||||
|
||||
为了以不同的进制转换整数字符串,简单的使用带有进制的int()函数即可:
|
||||
为了以不同的进制转换整数字符串,简单的使用带有进制的 ``int()`` 函数即可:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
@@ -51,8 +51,8 @@
|
||||
例如,IPv6网络地址使用一个128位的整数表示。
|
||||
如果你要从一个数据记录中提取这样的值的时候,你就会面对这样的问题。
|
||||
|
||||
作为一种替代方案,你可能想使用6.11小节中所介绍的struct模块来解压字节。
|
||||
这样也行得通,不过利用struct模块来解压对于整数的大小是有限制的。
|
||||
作为一种替代方案,你可能想使用6.11小节中所介绍的 ``struct`` 模块来解压字节。
|
||||
这样也行得通,不过利用 ``struct`` 模块来解压对于整数的大小是有限制的。
|
||||
因此,你可能想解压多个字节串并将结果合并为最终的结果,就像下面这样:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
4.47213595499958
|
||||
>>>
|
||||
|
||||
如果要执行其他的复数函数比如正弦、余弦或平方根,使用cmath模块:
|
||||
如果要执行其他的复数函数比如正弦、余弦或平方根,使用 ``cmath`` 模块:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
讨论
|
||||
----------
|
||||
Python中大部分与数学相关的模块都能处理复数。
|
||||
比如如果你使用numpy,可以很容易的构造一个复数数组并在这个数组上执行各种操作:
|
||||
比如如果你使用 ``numpy`` ,可以很容易的构造一个复数数组并在这个数组上执行各种操作:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -96,7 +96,7 @@ Python的标准数学函数确实情况下并不能产生复数值,因此你
|
||||
ValueError: math domain error
|
||||
>>>
|
||||
|
||||
如果你想生成一个复数返回结果,你必须显示的使用cmath模块,或者在某个支持复数的库中声明复数类型的使用。比如:
|
||||
如果你想生成一个复数返回结果,你必须显示的使用 ``cmath`` 模块,或者在某个支持复数的库中声明复数类型的使用。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
@@ -100,6 +100,6 @@ NaN值的一个特别的地方时它们之间的比较操作总是返回False。
|
||||
由于这个原因,测试一个NaN值得唯一安全的方法就是使用 ``math.isnan()`` ,也就是上面演示的那样。
|
||||
|
||||
有时候程序员想改变Python默认行为,在返回无穷大或NaN结果的操作中抛出异常。
|
||||
fpectl模块可以用来改变这种行为,但是它在标准的Python构建中并没有被启用,它是平台相关的,
|
||||
``fpectl`` 模块可以用来改变这种行为,但是它在标准的Python构建中并没有被启用,它是平台相关的,
|
||||
并且针对的是专家级程序员。可以参考在线的Python文档获取更多的细节。
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
----------
|
||||
解决方案
|
||||
----------
|
||||
fractions模块可以被用来执行包含分数的数学运算。比如:
|
||||
``fractions`` 模块可以被用来执行包含分数的数学运算。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
----------
|
||||
解决方案
|
||||
----------
|
||||
涉及到数组的重量级运算操作,可以使用NumPy库。
|
||||
NumPy的一个主要特征是它会给Python提供一个数组对象,相比标准的Python列表而已更适合用来做数学运算。
|
||||
下面是一个简单的小例子,向你展示标准列表对象和NumPy数组对象之间的差别:
|
||||
涉及到数组的重量级运算操作,可以使用 ``NumPy`` 库。
|
||||
``NumPy`` 的一个主要特征是它会给Python提供一个数组对象,相比标准的Python列表而已更适合用来做数学运算。
|
||||
下面是一个简单的小例子,向你展示标准列表对象和 ``NumPy`` 数组对象之间的差别:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -45,7 +45,7 @@ NumPy的一个主要特征是它会给Python提供一个数组对象,相比标
|
||||
>>>
|
||||
|
||||
正如所见,两种方案中数组的基本数学运算结果并不相同。
|
||||
特别的,numpy中的标量运算(比如 ``ax * 2`` 或 ``ax + 10`` )会作用在每一个元素上。
|
||||
特别的, ``NumPy`` 中的标量运算(比如 ``ax * 2`` 或 ``ax + 10`` )会作用在每一个元素上。
|
||||
另外,当两个操作数都是数组的时候执行元素对等位置计算,并最终生成一个新的数组。
|
||||
|
||||
对整个数组中所有元素同时执行数学运算可以使得作用在整个数组上的函数运算简单而又快速。
|
||||
@@ -60,7 +60,7 @@ NumPy的一个主要特征是它会给Python提供一个数组对象,相比标
|
||||
array([ 8, 15, 28, 47])
|
||||
>>>
|
||||
|
||||
NumPy还为数组操作提供了大量的通用函数,这些函数可以作为math模块中类似函数的替代。比如:
|
||||
``NumPy`` 还为数组操作提供了大量的通用函数,这些函数可以作为 ``math`` 模块中类似函数的替代。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -70,10 +70,10 @@ NumPy还为数组操作提供了大量的通用函数,这些函数可以作为
|
||||
array([ 0.54030231, -0.41614684, -0.9899925 , -0.65364362])
|
||||
>>>
|
||||
|
||||
使用这些通用函数要比循环数组并使用math模块中的函数执行计算要快的多。
|
||||
因此,只要有可能的话尽量选择numpy的数组方案。
|
||||
使用这些通用函数要比循环数组并使用 ``math`` 模块中的函数执行计算要快的多。
|
||||
因此,只要有可能的话尽量选择 ``NumPy`` 的数组方案。
|
||||
|
||||
底层实现中,NumPy数组使用了C或者Fortran语言的机制分配内存。
|
||||
底层实现中, ``NumPy`` 数组使用了C或者Fortran语言的机制分配内存。
|
||||
也就是说,它们是一个非常大的连续的并由同类型数据组成的内存区域。
|
||||
所以,你可以构造一个比普通Python列表大的多的数组。
|
||||
比如,如果你想构造一个10,000*10,000的浮点数二维网格,很轻松:
|
||||
@@ -120,7 +120,7 @@ NumPy还为数组操作提供了大量的通用函数,这些函数可以作为
|
||||
-0.54402111, -0.54402111]])
|
||||
>>>
|
||||
|
||||
关于NumPy有一点需要特别的主意,那就是它扩展Python列表的索引功能 - 特别是对于多维数组。
|
||||
关于 ``NumPy`` 有一点需要特别的主意,那就是它扩展Python列表的索引功能 - 特别是对于多维数组。
|
||||
为了说明清楚,先构造一个简单的二维数组并试着做些试验:
|
||||
|
||||
.. code-block:: python
|
||||
@@ -171,11 +171,11 @@ NumPy还为数组操作提供了大量的通用函数,这些函数可以作为
|
||||
----------
|
||||
讨论
|
||||
----------
|
||||
NumPy是Python领域中很多科学与工程库的基础,同时也是被广泛使用的最大最复杂的模块。
|
||||
``NumPy`` 是Python领域中很多科学与工程库的基础,同时也是被广泛使用的最大最复杂的模块。
|
||||
即便如此,在刚开始的时候通过一些简单的例子和玩具程序也能帮我们完成一些有趣的事情。
|
||||
|
||||
通常我们导入NumPy模块的时候会使用语句 ``import numpy as np`` 。
|
||||
这样的话你就不用再你的程序里面一遍遍的敲入numpy,只需要输入np就行了,节省了不少时间。
|
||||
通常我们导入 ``NumPy`` 模块的时候会使用语句 ``import numpy as np`` 。
|
||||
这样的话你就不用再你的程序里面一遍遍的敲入 ``numpy`` ,只需要输入 ``np`` 就行了,节省了不少时间。
|
||||
|
||||
如果想获取更多的信息,你当然得去NumPy官网逛逛了,网址是: http://www.numpy.org
|
||||
如果想获取更多的信息,你当然得去 ``NumPy`` 官网逛逛了,网址是: http://www.numpy.org
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
----------
|
||||
解决方案
|
||||
----------
|
||||
NumPy库有一个矩阵对象可以用来解决这个问题。
|
||||
``NumPy`` 库有一个矩阵对象可以用来解决这个问题。
|
||||
矩阵类似于3.9小节中数组对象,但是遵循线性代数的计算规则。下面的一个例子展示了矩阵的一些基本特性:
|
||||
|
||||
.. code-block:: python
|
||||
@@ -84,6 +84,6 @@ NumPy库有一个矩阵对象可以用来解决这个问题。
|
||||
讨论
|
||||
----------
|
||||
很显然线性代数是个非常大的主题,已经超出了本书能讨论的范围。
|
||||
但是,如果你需要操作数组和向量的话,NumPy是一个不错的入口点。
|
||||
可以访问NumPy官网 http://www.numpy.org 获取更多信息。
|
||||
但是,如果你需要操作数组和向量的话, ``NumPy`` 是一个不错的入口点。
|
||||
可以访问 ``NumPy`` 官网 http://www.numpy.org 获取更多信息。
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
----------
|
||||
解决方案
|
||||
----------
|
||||
random模块有大量的函数用来产生随机数和随机选择元素。
|
||||
``random`` 模块有大量的函数用来产生随机数和随机选择元素。
|
||||
比如,要想从一个序列中随机的抽取一个元素,可以使用 ``random.choice()`` :
|
||||
|
||||
.. code-block:: python
|
||||
@@ -100,7 +100,7 @@ random模块有大量的函数用来产生随机数和随机选择元素。
|
||||
----------
|
||||
讨论
|
||||
----------
|
||||
random模块使用Mersenne Twister算法来计算生成随机数。这是一个确定性算法,
|
||||
``random`` 模块使用 *Mersenne Twister* 算法来计算生成随机数。这是一个确定性算法,
|
||||
但是你可以通过 ``random.seed()`` 函数修改初始化种子。比如:
|
||||
|
||||
.. code-block:: python
|
||||
@@ -110,9 +110,9 @@ random模块使用Mersenne Twister算法来计算生成随机数。这是一个
|
||||
random.seed(b'bytedata') # Seed based on byte data
|
||||
|
||||
除了上述介绍的功能,random模块还包含基于均匀分布、高斯分布和其他分布的随机数生成函数。
|
||||
比如,``random.uniform()`` 计算均匀分布随机数,``random.gauss()`` 计算正态分布随机数。
|
||||
比如, ``random.uniform()`` 计算均匀分布随机数, ``random.gauss()`` 计算正态分布随机数。
|
||||
对于其他的分布情况请参考在线文档。
|
||||
|
||||
在random模块中的函数不应该用在和密码学相关的程序中。
|
||||
在 ``random`` 模块中的函数不应该用在和密码学相关的程序中。
|
||||
如果你确实需要类似的功能,可以使用ssl模块中相应的函数。
|
||||
比如,``ssl.RAND_bytes()`` 可以用来生成一个安全的随机字节序列。
|
||||
比如, ``ssl.RAND_bytes()`` 可以用来生成一个安全的随机字节序列。
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
----------
|
||||
解决方案
|
||||
----------
|
||||
为了执行不同时间单位的转换和计算,请使用datetime模块。
|
||||
比如,为了表示一个时间段,可以创建一个timedelta实例,就像下面这样:
|
||||
为了执行不同时间单位的转换和计算,请使用 ``datetime`` 模块。
|
||||
比如,为了表示一个时间段,可以创建一个 ``timedelta`` 实例,就像下面这样:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
58.5
|
||||
>>>
|
||||
|
||||
如果你想表示指定的日期和时间,先创建一个datetime实例然后使用标准的数学运算来操作它们。比如:
|
||||
如果你想表示指定的日期和时间,先创建一个 ``datetime`` 实例然后使用标准的数学运算来操作它们。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
2012-12-21 15:04:43.094063
|
||||
>>>
|
||||
|
||||
在计算的时候,需要注意的是datetime会自动处理闰年。比如:
|
||||
在计算的时候,需要注意的是 ``datetime`` 会自动处理闰年。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
----------
|
||||
讨论
|
||||
----------
|
||||
对大多数基本的日期和时间处理问题,datetime模块以及足够了。
|
||||
对大多数基本的日期和时间处理问题, ``datetime`` 模块以及足够了。
|
||||
如果你需要执行更加复杂的日期操作,比如处理时区,模糊时间范围,节假日计算等等,
|
||||
可以考虑使用 `dateutil模块 <http://pypi.python.org/pypi/python-dateutil>`_
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
----------
|
||||
解决方案
|
||||
----------
|
||||
Python的datetime模块中有工具函数和类可以帮助你执行这样的计算。
|
||||
Python的 ``datetime`` 模块中有工具函数和类可以帮助你执行这样的计算。
|
||||
下面是对类似这样的问题的一个通用解决方案:
|
||||
|
||||
.. code-block:: python
|
||||
@@ -54,7 +54,7 @@ Python的datetime模块中有工具函数和类可以帮助你执行这样的计
|
||||
datetime.datetime(2012, 8, 24, 22, 5, 9, 911393)
|
||||
>>>
|
||||
|
||||
可选的start_date参数可以由另外一个datetime实例来提供。比如:
|
||||
可选的 ``start_date`` 参数可以由另外一个 ``datetime`` 实例来提供。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -70,8 +70,8 @@ Python的datetime模块中有工具函数和类可以帮助你执行这样的计
|
||||
上面的算法原理是这样的:先将开始日期和目标日期映射到星期数组的位置上(星期一索引为0),
|
||||
然后通过模运算计算出目标日期要经过多少天才能到达开始日期。然后用开始日期减去那个时间差即得到结果日期。
|
||||
|
||||
如果你要像这样执行大量的日期计算的话,你最好安装第三方包python-dateutil来代替。
|
||||
比如,下面是是使用dateutil模块中的 ``relativedelta()`` 函数执行同样的计算:
|
||||
如果你要像这样执行大量的日期计算的话,你最好安装第三方包 ``python-dateutil`` 来代替。
|
||||
比如,下面是是使用 ``dateutil`` 模块中的 ``relativedelta()`` 函数执行同样的计算:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
你可以先计算出开始日期和结束日期,
|
||||
然后在你步进的时候使用 ``datetime.timedelta`` 对象递增这个日期变量即可。
|
||||
|
||||
下面是一个接受任意datetime对象并返回一个由当前月份开始日和下个月开始日组成的元组对象。
|
||||
下面是一个接受任意 ``datetime`` 对象并返回一个由当前月份开始日和下个月开始日组成的元组对象。
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -59,11 +59,11 @@
|
||||
上面的代码先计算出一个对应月份第一天的日期。
|
||||
一个快速的方法就是使用 ``date`` 或 ``datetime`` 对象的 ``replace()`` 方法简单的将 ``days`` 属性设置成1即可。
|
||||
``replace()`` 方法一个好处就是它会创建和你开始传入对象类型相同的对象。
|
||||
所以,如果输入参数是一个date实例,那么结果也是一个date实例。
|
||||
同样的,如果输入是一个datetime实例,那么你得到的就是一个datetime实例。
|
||||
所以,如果输入参数是一个 ``date`` 实例,那么结果也是一个 ``date`` 实例。
|
||||
同样的,如果输入是一个 ``datetime`` 实例,那么你得到的就是一个 ``datetime`` 实例。
|
||||
|
||||
然后,使用 ``calendar.monthrange()`` 函数来找出该月的总天数。
|
||||
任何时候只要你想获得日历信息,那么calendar模块就非常有用了。
|
||||
任何时候只要你想获得日历信息,那么 ``calendar`` 模块就非常有用了。
|
||||
``monthrange()`` 函数会返回包含星期和该月天数的元组。
|
||||
|
||||
一旦该月的天数已知了,那么结束日期就可以通过在开始日期上面加上这个天数获得。
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
讨论
|
||||
----------
|
||||
``datetime.strptime()`` 方法支持很多的格式化代码,
|
||||
比如 ``%Y`` 代表4位数年份,``%m`` 代表两位数月份。
|
||||
比如 ``%Y`` 代表4位数年份, ``%m`` 代表两位数月份。
|
||||
还有一点值得注意的是这些格式化占位符也可以反过来使用,将日期输出为指定的格式字符串形式。
|
||||
|
||||
比如,假设你的代码中生成了一个 ``datetime`` 对象,
|
||||
@@ -46,10 +46,10 @@
|
||||
'Sunday September 23, 2012'
|
||||
>>>
|
||||
|
||||
还有一点需要注意的是,``strptime()`` 的性能要比你想象中的差很多,
|
||||
还有一点需要注意的是, ``strptime()`` 的性能要比你想象中的差很多,
|
||||
因为它是使用纯Python实现,并且必须处理所有的系统本地设置。
|
||||
如果你要在代码中需要解析大量的日期并且已经知道了日期字符串的确切格式,可以自己实现一套解析方案来获取更好的性能。
|
||||
比如,如果你已经知道所以日期格式是"YYYY-MM-DD",你可以像下面这样实现一个解析函数:
|
||||
比如,如果你已经知道所以日期格式是 ``YYYY-MM-DD`` ,你可以像下面这样实现一个解析函数:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
对几乎所有涉及到时区的问题,你都应该使用 ``pytz`` 模块。这个包提供了Olson时区数据库,
|
||||
它是时区信息的事实上的标准,在很多语言和操作系统里面都可以找到。
|
||||
|
||||
pytz模块一个主要用途是将 ``datetime`` 库创建的简单日期对象本地化。
|
||||
``pytz`` 模块一个主要用途是将 ``datetime`` 库创建的简单日期对象本地化。
|
||||
比如,下面如何表示一个芝加哥时间的示例:
|
||||
|
||||
.. code-block:: python
|
||||
@@ -109,5 +109,5 @@ pytz模块一个主要用途是将 ``datetime`` 库创建的简单日期对象
|
||||
['Asia/Kolkata']
|
||||
>>>
|
||||
|
||||
注:当你阅读到这里的时候,有可能pytz模块以及不再建议使用了,因为PEP431提出了更先进的时区支持。
|
||||
注:当你阅读到这里的时候,有可能 ``pytz`` 模块以及不再建议使用了,因为PEP431提出了更先进的时区支持。
|
||||
但是这里谈到的很多问题还是有参考价值的(比如使用UTC日期的建议等)。
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
except StopIteration:
|
||||
pass
|
||||
|
||||
通常来讲,``StopIteration`` 用来指示迭代的结尾。
|
||||
然而,如果你手动使用上面演示的 ``next()`` 函数的话,你还可以通过返回一个指定值来标记结尾,比如None。
|
||||
通常来讲, ``StopIteration`` 用来指示迭代的结尾。
|
||||
然而,如果你手动使用上面演示的 ``next()`` 函数的话,你还可以通过返回一个指定值来标记结尾,比如 ``None`` 。
|
||||
下面是示例:
|
||||
|
||||
.. code-block:: python
|
||||
@@ -44,7 +44,7 @@
|
||||
----------
|
||||
讨论
|
||||
----------
|
||||
大多数情况下,我们会使用for循环语句用来遍历一个可迭代对象。
|
||||
大多数情况下,我们会使用 ``for`` 循环语句用来遍历一个可迭代对象。
|
||||
但是,偶尔也需要对迭代做更加精确的控制,这时候了解底层迭代机制就显得尤为重要了。
|
||||
|
||||
下面的交互示例向我们演示了迭代期间所发生的基本细节:
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
for ch in root:
|
||||
print(ch)
|
||||
|
||||
在上面代码中,``__iter__()`` 方法只是简单的将迭代请求传递给内部的 ``_children`` 属性。
|
||||
在上面代码中, ``__iter__()`` 方法只是简单的将迭代请求传递给内部的 ``_children`` 属性。
|
||||
|
||||
|
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
----------
|
||||
讨论
|
||||
----------
|
||||
一个函数中需要有一个yield语句即可将其转换为一个生成器。
|
||||
一个函数中需要有一个 ``yield`` 语句即可将其转换为一个生成器。
|
||||
跟普通函数不同的是,生成器只能用于迭代操作。
|
||||
下面是一个实验,向你展示这样的函数底层工作机制:
|
||||
|
||||
@@ -88,6 +88,6 @@
|
||||
StopIteration
|
||||
>>>
|
||||
|
||||
一个生成器函数主要特征是它只会回应在迭代中使用到的"next"操作。
|
||||
一个生成器函数主要特征是它只会回应在迭代中使用到的 *next* 操作。
|
||||
一旦生成器函数返回退出,迭代终止。我们在迭代中通常使用的for语句会自动处理这些细节,所以你无需担心。
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
解决方案
|
||||
----------
|
||||
如果你想让你的生成器暴露外部状态给用户,
|
||||
别忘了你可以简单的将它实现为一个类,然后把生成器函数放到__iter__()方法中过去。比如:
|
||||
别忘了你可以简单的将它实现为一个类,然后把生成器函数放到 ``__iter__()`` 方法中过去。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
15
|
||||
>>>
|
||||
|
||||
在这个例子中,``islice()`` 函数最后那个 ``None`` 参数指定了你要获取从第3个到最后的所有元素,
|
||||
在这个例子中, ``islice()`` 函数最后那个 ``None`` 参数指定了你要获取从第3个到最后的所有元素,
|
||||
如果 ``None`` 和3的位置对调,意思就是仅仅获取前三个元素恰恰相反,
|
||||
(这个跟切片的相反操作 ``[3:]`` 和 ``[:3]`` 原理是一样的)。
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ itertools模块提供了三个函数来解决这类问题。
|
||||
----------
|
||||
讨论
|
||||
----------
|
||||
这一小节我们向你展示的仅仅是itertools模块的一部分功能。
|
||||
这一小节我们向你展示的仅仅是 ``itertools`` 模块的一部分功能。
|
||||
尽管你也可以自己手动实现排列组合算法,但是这样做得要花点脑力。
|
||||
当我们碰到看上去有些复杂的迭代问题时,最好可以先去看看itertools模块。
|
||||
如果这个问题很普遍,那么很有可能会在里面找到解决方案!
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
(3, 12, 'z')
|
||||
>>>
|
||||
|
||||
最后强调一点就是,``zip()`` 会创建一个迭代器来作为结果返回。
|
||||
最后强调一点就是, ``zip()`` 会创建一个迭代器来作为结果返回。
|
||||
如果你需要将结对的值存储在列表中,要使用 ``list()`` 函数。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
for x in chain(a, b):
|
||||
...
|
||||
|
||||
第一种方案中,``a + b`` 操作会创建一个全新的序列并要求a和b的类型一致。
|
||||
第一种方案中, ``a + b`` 操作会创建一个全新的序列并要求a和b的类型一致。
|
||||
``chian()`` 不会有这一步,所以如果输入序列非常大的时候会很省内存。
|
||||
并且当可迭代对象类型不一样的时候 ``chain()`` 同样可以很好的工作。
|
||||
|
||||
|
||||
@@ -120,9 +120,9 @@
|
||||
----------
|
||||
以管道方式处理数据可以用来解决各类其他问题,包括解析,读取实时数据,定时轮询等。
|
||||
|
||||
为了理解上述代码,重点是要明白yield语句作为数据的生产者而for循环语句作为数据的消费者。
|
||||
当这些生成器被连在一起后,每个yield会将一个单独的数据元素传递给迭代处理管道的下一阶段。
|
||||
在例子最后部分,``sum()`` 函数是最终的程序驱动者,每次从生成器管道中提取出一个元素。
|
||||
为了理解上述代码,重点是要明白 ``yield`` 语句作为数据的生产者而 ``for`` 循环语句作为数据的消费者。
|
||||
当这些生成器被连在一起后,每个 ``yield`` 会将一个单独的数据元素传递给迭代处理管道的下一阶段。
|
||||
在例子最后部分, ``sum()`` 函数是最终的程序驱动者,每次从生成器管道中提取出一个元素。
|
||||
|
||||
这种方式一个非常好的特点是每个生成器函数很小并且都是独立的。这样的话就很容易编写和维护它们了。
|
||||
很多时候,这些函数如果比较通用的话可以在其他场景重复使用。
|
||||
@@ -140,7 +140,7 @@
|
||||
等到下一个迭代步骤时文件就关闭了,因此 ``china()`` 在这里不能这样使用。
|
||||
上面的方案可以避免这种情况。
|
||||
|
||||
``gen_concatenate()`` 函数中出现过 ``yield from`` 语句,它将yield操作代理到父生成器上去。
|
||||
``gen_concatenate()`` 函数中出现过 ``yield from`` 语句,它将 ``yield`` 操作代理到父生成器上去。
|
||||
语句 ``yield from it`` 简单的返回生成器 ``it`` 所产生的所有值。
|
||||
关于这个我们在4.14小节会有更进一步的描述。
|
||||
|
||||
@@ -148,7 +148,7 @@
|
||||
有时候你想立即处理所有数据。
|
||||
然而,即便是这种情况,使用生成器管道也可以将这类问题从逻辑上变为工作流的处理方式。
|
||||
|
||||
David Beazley在他的
|
||||
*David Beazley* 在他的
|
||||
`Generator Tricks for Systems Programmers <http://www.dabeaz.com/generators/>`_
|
||||
教程中对于这种技术有非常深入的讲解。可以参考这个教程获取更多的信息。
|
||||
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
for x in flatten(items):
|
||||
print(x)
|
||||
|
||||
在上面代码中,``isinstance(x, Iterable)`` 检查某个元素是否是可迭代的。
|
||||
如果是的话,``yield from`` 就会返回所有子例程的值。最终返回结果就是一个没有嵌套的简单序列了。
|
||||
在上面代码中, ``isinstance(x, Iterable)`` 检查某个元素是否是可迭代的。
|
||||
如果是的话, ``yield from`` 就会返回所有子例程的值。最终返回结果就是一个没有嵌套的简单序列了。
|
||||
|
||||
额外的参数 ``ignore_types`` 和检测语句 ``isinstance(x, ignore_types)``
|
||||
用来将字符串和字节排除在可迭代对象外,防止将它们再展开成单个的字符。
|
||||
@@ -55,7 +55,7 @@
|
||||
讨论
|
||||
----------
|
||||
语句 ``yield from`` 在你想在生成器中调用其他生成器作为子例程的时候非常有用。
|
||||
如果你不使用它的话,那么就必须写额外的for循环了。比如:
|
||||
如果你不使用它的话,那么就必须写额外的 ``for`` 循环了。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -72,6 +72,6 @@
|
||||
之前提到的对于字符串和字节的额外检查是为了防止将它们再展开成单个字符。
|
||||
如果还有其他你不想展开的类型,修改参数 ``ignore_types`` 即可。
|
||||
|
||||
最后要注意的一点是,``yield from`` 在涉及到基于协程和生成器的并发编程中扮演着更加重要的角色。
|
||||
最后要注意的一点是, ``yield from`` 在涉及到基于协程和生成器的并发编程中扮演着更加重要的角色。
|
||||
可以参考12.12小节查看另外一个例子。
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
----------
|
||||
问题
|
||||
----------
|
||||
你在代码中使用while循环来迭代处理数据,因为它需要调用某个函数或者和一般迭代模式不同的测试条件。
|
||||
你在代码中使用 ``while`` 循环来迭代处理数据,因为它需要调用某个函数或者和一般迭代模式不同的测试条件。
|
||||
能不能用迭代器来重写这个循环呢?
|
||||
|
||||
|
|
||||
@@ -59,6 +59,6 @@
|
||||
当以这种方式使用的时候,它会创建一个迭代器, 这个迭代器会不断调用 ``callable`` 对象直到返回值和标记值相等为止。
|
||||
|
||||
这种特殊的方法对于一些特定的会被重复调用的函数很有效果,比如涉及到I/O调用的函数。
|
||||
举例来讲,如果你想从套接字或文件中以数据块的方式读取数据,通常你得要不断重复的执行 ``read()`` 或 ``recv()``,
|
||||
举例来讲,如果你想从套接字或文件中以数据块的方式读取数据,通常你得要不断重复的执行 ``read()`` 或 ``recv()`` ,
|
||||
并在后面紧跟一个文件结尾测试来决定是否终止。这节中的方案使用一个简单的 ``iter()`` 调用就可以将两者结合起来了。
|
||||
其中lambda函数参数是为了创建一个无参的callable对象,并为 ``recv`` 或 ``read()`` 方法提供了size参数。
|
||||
其中 ``lambda`` 函数参数是为了创建一个无参的 ``callable`` 对象,并为 ``recv`` 或 ``read()`` 方法提供了 ``size`` 参数。
|
||||
|
||||
@@ -69,7 +69,7 @@ latin-1是字节0-255到U+0000至U+00FF范围内Unicode字符的直接映射。
|
||||
----------
|
||||
读写文本文件一般来讲是比较简单的。但是也几点是需要注意的。
|
||||
首先,在例子程序中的with语句给被使用到的文件创建了一个上下文环境,
|
||||
但with控制块结束时,文件会自动关闭。你也可以不使用with语句,但是这时候你就必须记得手动关闭文件:
|
||||
但 ``with`` 控制块结束时,文件会自动关闭。你也可以不使用 ``with`` 语句,但是这时候你就必须记得手动关闭文件:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
----------
|
||||
问题
|
||||
----------
|
||||
你想将print()函数的输出重定向到一个文件中去。
|
||||
你想将 ``print()`` 函数的输出重定向到一个文件中去。
|
||||
|
||||
|
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
----------
|
||||
问题
|
||||
----------
|
||||
你想使用print()函数输出数据,但是想改变默认的分隔符或者行尾符。
|
||||
你想使用 ``print()`` 函数输出数据,但是想改变默认的分隔符或者行尾符。
|
||||
|
||||
|
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
----------
|
||||
解决方案
|
||||
----------
|
||||
可以在 ``open()`` 函数中使用x模式来代替w模式的方法来解决这个问题。比如:
|
||||
可以在 ``open()`` 函数中使用 ``x`` 模式来代替 ``w`` 模式的方法来解决这个问题。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
@@ -53,6 +53,6 @@
|
||||
比如,在单元测试中,你可以使用 ``StringIO`` 来创建一个包含测试数据的类文件对象,
|
||||
这个对象可以被传给某个参数为普通文件对象的函数。
|
||||
|
||||
需要注意的是,``StringIO`` 和 ``BytesIO`` 实例并没有正确的整数类型的文件描述符。
|
||||
需要注意的是, ``StringIO`` 和 ``BytesIO`` 实例并没有正确的整数类型的文件描述符。
|
||||
因此,它们不能在那些需要使用真实的系统级文件如文件,管道或者是套接字的程序中使用。
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
f.write(text)
|
||||
|
||||
如上,所有的I/O操作都使用文本模式并执行Unicode的编码/解码。
|
||||
类似的,如果你想操作二进制数据,使用rb或者wb文件模式即可。
|
||||
类似的,如果你想操作二进制数据,使用 ``rb`` 或者 ``wb`` 文件模式即可。
|
||||
|
||||
|
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
|
||||
默认的等级是9,也是最高的压缩等级。等级越低性能越好,但是数据压缩程度也越低。
|
||||
|
||||
最后一点,``gzip.open()`` 和 ``bz2.open()`` 还有一个很少被知道的特性,
|
||||
最后一点, ``gzip.open()`` 和 ``bz2.open()`` 还有一个很少被知道的特性,
|
||||
它们可以作用在一个已存在并以二进制模式打开的文件上。比如,下面代码是可行的:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
``iter()`` 函数有一个鲜为人知的特性就是,如果你给它传递一个可调用对象和一个标记值,它会创建一个迭代器。
|
||||
这个迭代器会一直调用传入的可调用对象直到它返回标记值为止,这时候迭代终止。
|
||||
|
||||
在例子中,``functools.partial`` 用来创建一个每次被调用时从文件中读取固定数目字节的可调用对象。
|
||||
在例子中, ``functools.partial`` 用来创建一个每次被调用时从文件中读取固定数目字节的可调用对象。
|
||||
标记值 ``b''`` 就是当到达文件结尾时的返回值。
|
||||
|
||||
最后再提一点,上面的例子中的文件时以二进制模式打开的。
|
||||
|
||||
@@ -50,8 +50,8 @@
|
||||
----------
|
||||
讨论
|
||||
----------
|
||||
文件对象的 ``readinto()`` 方法能被用来为预先分配内存的数组填充数据,甚至包括由array模块或numpy库创建的数组。
|
||||
和普通 ``read()`` 方法不同的是,``readinto()`` 填充已存在的缓冲区而不是为新对象重新分配内存再返回它们。
|
||||
文件对象的 ``readinto()`` 方法能被用来为预先分配内存的数组填充数据,甚至包括由 ``array`` 模块或 ``numpy`` 库创建的数组。
|
||||
和普通 ``read()`` 方法不同的是, ``readinto()`` 填充已存在的缓冲区而不是为新对象重新分配内存再返回它们。
|
||||
因此,你可以使用它来避免大量的内存分配操作。
|
||||
比如,如果你读取一个由相同大小的记录组成的二进制文件时,你可以像下面这样写:
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
|
||||
如果字节数小于缓冲区大小,表明数据被截断或者被破坏了(比如你期望每次读取指定数量的字节)。
|
||||
|
||||
最后,留心观察其他函数库和模块中和 ``into`` 相关的函数(比如recv_into(),pack_into()等)。
|
||||
最后,留心观察其他函数库和模块中和 ``into`` 相关的函数(比如 ``recv_into()`` , ``pack_into()`` 等)。
|
||||
Python的很多其他部分已经能支持直接的I/O或数据访问操作,这些操作可被用来填充或修改数组和缓冲区内容。
|
||||
|
||||
关于解析二进制结构和 ``memoryviews`` 使用方法的更高级例子,请参考6.12小节。
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
True
|
||||
>>>
|
||||
|
||||
默认情况下,``memeory_map()`` 函数打开的文件同时支持读和写操作。
|
||||
默认情况下, ``memeory_map()`` 函数打开的文件同时支持读和写操作。
|
||||
任何的修改内容都会复制回原来的文件中。
|
||||
如果需要只读的访问模式,可以给参数 ``access`` 赋值为 ``mmap.ACCESS_READ`` 。比如:
|
||||
|
||||
@@ -94,10 +94,10 @@
|
||||
讨论
|
||||
----------
|
||||
为了随机访问文件的内容,使用 ``mmap`` 将文件映射到内存中是一个高效和优雅的方法。
|
||||
例如,你无需打开一个文件并执行大量的 ``seek()`` ,``read()`` ,``write()`` 调用,
|
||||
例如,你无需打开一个文件并执行大量的 ``seek()`` , ``read()`` , ``write()`` 调用,
|
||||
只需要简单的映射文件并使用切片操作访问数据即可。
|
||||
|
||||
一般来讲,``mmap()`` 所暴露的内存看上去就是一个二进制数组对象。
|
||||
一般来讲, ``mmap()`` 所暴露的内存看上去就是一个二进制数组对象。
|
||||
但是,你可以使用一个内存视图来解析其中的数据。比如:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -5,31 +5,33 @@
|
||||
----------
|
||||
问题
|
||||
----------
|
||||
You need to get the terminal size in order to properly format the output of your program.
|
||||
你需要知道当前终端的大小以便正确的格式化输出。
|
||||
|
||||
|
|
||||
|
||||
----------
|
||||
解决方案
|
||||
----------
|
||||
Use the os.get_terminal_size() function to do this:
|
||||
使用 ``os.get_terminal_size()`` 函数来做到这一点。
|
||||
|
||||
>>> import os
|
||||
>>> sz = os.get_terminal_size()
|
||||
>>> sz
|
||||
os.terminal_size(columns=80, lines=24)
|
||||
>>> sz.columns
|
||||
80
|
||||
>>> sz.lines
|
||||
24
|
||||
>>>
|
||||
代码示例:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import os
|
||||
>>> sz = os.get_terminal_size()
|
||||
>>> sz
|
||||
os.terminal_size(columns=80, lines=24)
|
||||
>>> sz.columns
|
||||
80
|
||||
>>> sz.lines
|
||||
24
|
||||
>>>
|
||||
|
||||
|
|
||||
|
||||
----------
|
||||
讨论
|
||||
----------
|
||||
There are many other possible approaches for obtaining the terminal size, ranging from
|
||||
reading environment variables to executing low-level system calls involving ioctl()
|
||||
and TTYs. Frankly, why would you bother with that when this one simple call will
|
||||
suffice?
|
||||
有太多方式来得知终端大小了,从读取环境变量到执行底层的 ``ioctl()`` 函数等等。
|
||||
不过,为什么要去研究这些复杂的办法而不是仅仅调用一个简单的函数呢?
|
||||
|
||||
@@ -59,9 +59,9 @@ True
|
||||
32
|
||||
>>> print(cfg.get('server','signature'))
|
||||
|
||||
=================================
|
||||
\=================================
|
||||
Brought to you by the Python Cookbook
|
||||
=================================
|
||||
\=================================
|
||||
>>>
|
||||
|
||||
If desired, you can also modify the configuration and write it back to a file using the
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
Python提供了大量的内置数据结构,包括列表,集合以及字典。大多数情况下使用这些数据结构式很简单的。
|
||||
但是,我们也会经常碰到到诸如查询,排序和过滤等等这些普遍存在的问题。
|
||||
因此,这一章的目的就是讨论这些比较常见的问题和算法。
|
||||
另外,我们也会给出在集合模块collections当中操作这些数据结构的方法。
|
||||
另外,我们也会给出在集合模块 ``collections`` 当中操作这些数据结构的方法。
|
||||
|
||||
|
||||
Contents:
|
||||
|
||||
Reference in New Issue
Block a user