# Python 之优雅与瑕疵，第 1 部分

## 不可比较的麻烦

##### 清单 1. 比较是否成功取决于类型和值
```>>> map(type, (u1, s1, s2))
[<type 'unicode'>, <type 'str'>, <type 'str'>]

>>> u1 < s1
True

>>> s1 < s2
True

>>> u1 < s2
UnicodeDecodeError: 'ascii' codec can't decode byte 0xf0 in position 0:
ordinal not in range(128)

>>> map(type, (n, j, u1))
[<type 'int'>, <type 'complex'>, <type 'unicode'>]

>>> n < u1
True

>>> j < u1
True

>>> n < j
TypeError: no ordering relation is defined for complex numbers```

##### 清单 2. 令人吃惊的比较结果
```>>> 2-3j < 'spam'
True

>>> 4+0j < decimal.Decimal('3.14')
True

>>> 4+0j < 5+0j
TypeError: no ordering relation is defined for complex numbers```

### 一个真正的瑕疵：对异构集合进行排序

##### 清单 3. 根据两个列表的成员关系执行不同的操作
```list1.sort()
list2.sort()
list2_xtra = []
list2_ndx = 0
for it1 in list1:
it2 = list2[list2_ndx]
while it1 < it2:
list2_ndx += 1
it2 = list2[list2_ndx]
if it1 == it2:
item_in_both(it1)
elif it1 > it2:
item_in_list1(it1)
else:
list2_xtra.appen(it2)
for it2 in list2_xtra:
item_in_list2(it2)```

### 排序失败

##### 清单 4. 可排序和不可排序列表的大杂烩
```['x','y','z', 1],
['x','y','z', 1j],
['x','y','z', 1j, 1],       # Adding an element makes it unsortable
[0j, 1j, 2j],               # An obvious "natural" order
[0j, 1, 2],
[0, 1, 2],                  # Notice that 0==0j --> True
[chr(120), chr(240)],
[chr(120), chr(240), 'x'],
[chr(120), chr(240), u'x'], # Notice u'x'=='x' --> True
[u'a', 'b', chr(240)],
[chr(240), u'a', 'b']       # Same items, different initial order```

##### 清单 5. 对各列表进行排序的结果
```% python compare.py
(0)  ['x', 'y', 'z', 1] --> [1, 'x', 'y', 'z']
(1)  ['x', 'y', 'z', 1j] --> [1j, 'x', 'y', 'z']
(2)  ['x', 'y', 'z', 1j, 1] --> exceptions.TypeError
(3)  [0j, 1j, 2j] --> exceptions.TypeError
(4)  [0j, 1, 2] --> exceptions.TypeError
(5)  [0, 1, 2] --> [0, 1, 2]
(6)  ['x', '\xf0'] --> ['x', '\xf0']
(7)  ['x', '\xf0', 'x'] --> ['x', 'x', '\xf0']
(8)  ['x', '\xf0', u'x'] --> exceptions.UnicodeDecodeError
(9)  [u'a', 'b', '\xf0'] --> [u'a', 'b', '\xf0']
(10) ['\xf0', u'a', 'b'] --> exceptions.UnicodeDecodeError```

### 修订比较

##### 清单 6. 集与集操作
```>>> set1 = set([1j, u'2', 3, 4.0])

>>> set2 = set([4, 3, 2, 1])

>>> set1 | set2
set([3, 1, 2, 1j, 4.0, u'2'])

>>> set1 & set2
set([3, 4])```

##### 清单 7. 集中得到的奇怪类型
```>>> set2 & set1
set([3, 4.0])

>>> set([3, 4.0, 4, 4+0j])
set([3, 4.0])```

##### 清单 8. 一个稳定、通用的排序键
```def stablesort(o):
# Use as: mylist.sort(key=stablesort)
if type(o) is complex:
return (type(o), o.real, o.imag)
else:
return (type(o), o)```

## 以生成器作为准序列

Python 的发展大方向是以惰性方式构造类似于序列的对象；总体来说，这个方向是正确的。惰性的伪序列既可以节省内存空间，还可以提高操作的速度（尤其是在处理非常大的与序列类似的 “东西” 时）。

### 分歧

##### 清单 9. 与序列和迭代器相似的东西
```>>> r = range(10)

>>> i = iter(r)

>>> x = xrange(10)

>>> g = itertools.takewhile(lambda n: n<10, itertools.count())

#...etc...```

##### 清单 10. 索引操作成功和失败的示例
```>>> r[4]
4

>>> i[4]
TypeError: unindexable object```

##### 清单 11. 获得索引的怪方法
```>>> thing, temp = itertools.tee(thing)

>>> zip(temp, '.'*5)[-1][0]
4```

`itertools.tee()` 的预调用保留了原始迭代器。对于切片，可以按照特殊方式使用 `itertools.islice()` 函数。

##### 清单 12. 获得一个切片的特殊方法
```>>> r[4:9:2]
[4, 6, 8]

>>> list(itertools.islice(r,4,9,2))  # works for iterators
[4, 6, 8]```

### 类包装器

##### 清单 13. 使迭代器可编制索引
```>>> class Indexable(object):
...     def __init__(self, it):
...         self.it = it
...     def __getitem__(self, x):
...         self.it, temp = itertools.tee(self.it)
...         if type(x) is slice:
...             return list(itertools.islice(self.it, x.start, x.stop, x.step))
...         else:
...             return zip(temp, range(x+1))[-1][0]
...     def __iter__(self):
...         self.it, temp = itertools.tee(self.it)
...         return temp
...

>>> integers = Indexable(itertools.count())

>>> integers[4]
4
>>> integers[4:9:2]
[4, 6, 8]```

#### 评论

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Linux, Open source
ArticleID=216268
ArticleTitle=可爱的 Python: Python 之优雅与瑕疵，第 1 部分
publish-date=04292007