Python编程:生成器、迭代器与装饰器的深度解析
立即解锁
发布时间: 2025-08-18 00:44:30 订阅数: 4 

### Python编程:生成器、迭代器与装饰器的深度解析
#### 1. 生成器表达式
Python为在序列上编写简单生成器提供了快捷方式。可以使用类似于列表推导式的语法来替代`yield`,只需将方括号替换为圆括号。例如:
```python
iter = (x**2 for x in range(10) if x % 2 == 0)
for el in iter:
print el
```
这种表达式被称为生成器表达式或`genexp`。它们的使用方式与列表推导式类似,用于减少代码序列的大小。与列表推导式不同的是,它们不会提前计算整个序列,而是像常规生成器一样逐个生成元素。因此,在对`yield`表达式进行简单循环,或者替换可以作为迭代器的列表推导式时,都应该使用生成器表达式。
#### 2. itertools模块
当Python引入迭代器时,提供了一个新的模块`itertools`来实现常见模式。由于它是用C语言编写的,因此提供了最高效的迭代器。`itertools`涵盖了许多模式,其中最有趣的是`islice`、`tee`和`groupby`。
##### 2.1 islice:窗口迭代器
`islice`返回一个迭代器,该迭代器作用于序列的一个子组。以下示例读取标准输入中的行,并在每行元素多于四个时,从第五个元素开始生成:
```python
import itertools
def starting_at_five():
value = raw_input().strip()
while value != '':
for el in itertools.islice(value.split(), 4, None):
yield el
value = raw_input().strip()
iter = starting_at_five()
print(iter.next())
```
可以在每次需要从流中提取特定位置的数据时使用`islice`。例如,对于使用记录的特殊格式文件,或者像SOAP信封那样包含元数据封装数据的流,`islice`可以看作是在每行数据上滑动的窗口。
##### 2.2 tee:前后迭代器
迭代器会消耗它所处理的序列,一旦处理就无法回头。`tee`提供了一种模式,可以在一个序列上运行多个迭代器。这有助于在获得第一次运行的信息后再次处理数据。例如,在处理文件之前读取文件的头部可以提供其性质的信息:
```python
import itertools
def with_head(iterable, headsize=1):
a, b = itertools.tee(iterable)
return list(itertools.islice(a, headsize)), b
seq = [1, 2, 3, 4, 5]
print(with_head(seq))
print(with_head(seq, 4))
```
在这个函数中,如果使用`tee`生成两个迭代器,第一个迭代器与`islice`一起使用,以获取迭代的前`headsize`个元素,并将它们作为扁平列表返回。返回的第二个元素是一个全新的迭代器,可用于对整个序列进行操作。
##### 2.3 groupby:唯一迭代器
这个函数的工作方式有点像Unix命令`uniq`。它能够对迭代器中的重复元素进行分组,只要这些元素是相邻的。可以为该函数提供一个函数来比较元素,否则将使用身份比较。
一个使用`groupby`的示例是使用游程编码(RLE)压缩数据。字符串中每组相邻的重复字符将被字符本身和出现次数替换。当字符单独出现时,使用1。例如:
```plaintext
get uuuuuuuuuuuuuuuuuup
```
将被替换为:
```plaintext
1g1e1t1 8u1p
```
使用`groupby`实现RLE只需要几行代码:
```python
from itertools import groupby
def compress(data):
return ((len(list(group)), name) for name, group in groupby(data))
def decompress(data):
return (car * size for size, car in data)
print(list(compress('get uuuuuuuuuuuuuuuuuup')))
compressed = compress('get uuuuuuuuuuuuuuuuuup')
print(''.join(decompress(compressed)))
```
如果对压缩感兴趣,可以考虑LZ77算法,它是RLE的增强版本,寻找相邻的匹配模式而不是匹配字符:[http://en.wikipedia.org/wiki/LZ77](http://en.wikipedia.org/wiki/LZ77)。
##### 2.4 其他函数
[http://docs.python.org/lib/itertools-functions.html](http://docs.python.org/lib/itertools-functions.html)提供了`itertools`函数的详尽列表,这里介绍一些常用的函数:
| 函数 | 描述 |
| --- | --- |
| `chain(*iterables)` | 创建一个迭代器,依次迭代每个可迭代对象 |
| `count([n])` | 返回一个迭代器,提供连续的整数,可从0或指定的`n`开始 |
| `cycle(iterable)` | 迭代可迭代对象的每个元素,然后重新开始,无限重复 |
| `dropwhile(predicate, iterable)` | 只要谓词返回`True`,就丢弃可迭代对象中的元素,当谓词返回`False`时,开始生成其余元素 |
| `ifilter(predicate, iterable)` | 类似于内置的`filter`函数 |
| `ifilterfalse(predicate, iterable)` | 与`ifilter`类似,但在谓词为`False`时迭代元素 |
| `imap(function, *iterables)` | 类似于内置的`map`函数,但作用于多个可迭代对象,当最短的可迭代对象耗尽时停止 |
| `izip(*iterables)` | 工作方式类似于`zip`,但返回一个迭代器 |
| `repeat(object[, times])` | 返回一个迭代器,每次调用都返回`object`,可指定重复次数或无限重复 |
| `starmap(function, iterable)` | 类似于`imap`,但将可迭代对象的元素作为星号参数传递给函数,当返回的元素是可以作为参数传递给函数的元组时很有用 |
| `takewhile(predicate, iterable)` | 返回可迭代对象中的元素,当谓词变为`False`时停止 |
#### 3. 装饰器
装饰器在Python 2.4中被引入,用于使函数和方法包装(接收一个函数并返回一个增强版本的函数)更易于阅读和理解。最初的用例是能够在方法定义的头部将方法定义为类方法或静态方法。在装饰器出现之前的语法如下:
```python
class WhatFor(object):
def it(cls):
print 'work with %s' % cls
it = classmethod(it)
def uncommon():
print 'I could be a global function'
uncommon = staticmethod(uncommon)
```
当方法变得复杂或对方法进行多次转换时,这种语法变得难以阅读。装饰器语法更简洁易懂:
```python
class WhatFor(object):
@classmethod
def it(cls):
print 'work with %s' % cls
@staticmethod
def uncommon():
print 'I could be a global function'
this_is = WhatFor()
this_is.it()
this_is.uncommon()
```
装饰器出现后,社区中的许多开发者开始使用它们,因为它们成为了实现某些模式的明显方式。以下将介绍如何编写装饰器,并提供一些示例。
#### 4. 如何编写装饰器
编写自定义装饰器有多种方法,但最简单、最易读的方法是编写一个返回子函数的函数,该子函数包装原始函数调用。通用模式如下:
```python
def mydecorator(function):
def _myde
```
0
0
复制全文
相关推荐










