range
range能夠用來表示給定範圍的整數,但是它並不保存那些整數。如下,當要選取45006230的元素時,才計算10000+45006230作爲返回值。
>>> r = range(10000, 1000000000)
>>> r[45006230]
45016230
迭代器
迭代器能夠給提供一個接一個連續獲取值的功能。
使用內建函數iter和next函數實現,當沒有更多的元素可被獲取時,系統會報錯,可使用try-except不讓其報錯。
>>> primes = [2, 3, 5, 7]
>>> type(primes)
<class 'list'>
>>> iterator = iter(primes)
>>> type(iterator)
<class 'list_iterator'>
>>> next(iterator)
2
>>> next(iterator)
3
>>> next(iterator)
5
>>> next(iterator)
7
>>> next(iterator)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>> try:
next(iterator)
except StopIteration:
print('No more values')
No more values
內建迭代器
map
函數在調用時不會指定運算,而是創建一個迭代對象。當使用next函數取值時會返回值。
>>> def double_and_print(x):
print('***', x, '=>', 2*x, '***')
return 2*x
>>> s = range(3, 7)
>>> doubled = map(double_and_print, s) # double_and_print not yet called
>>> next(doubled) # double_and_print called once
*** 3 => 6 ***
6
>>> next(doubled) # double_and_print called again
*** 4 => 8 ***
8
>>> list(doubled) # double_and_print called twice more
*** 5 => 10 ***
*** 6 => 12 ***
[10, 12]
類似的還有filter
和zip
函數。
生成器
生成器最明顯的特點就是不同return返回值,而是使用yield返回值。生成器不使用對象的屬性在序列中跟蹤其進度。相反,它們控制生成器函數的執行,每次調用生成器上的next時,該函數將一直運行,直到執行下一個yield語句。
>>> def letters_generator():
current = 'a'
while current <= 'd':
yield current
current = chr(ord(current)+1)
>>> for letter in letters_generator():
print(letter)
a
b
c
d
yield聲明標識函數是一個生成器函數。每次調用生成器函數時,不返回特定的值,而是返回一個生成器。next函數調用生成器得到下一個值,只有當next函數調用時,生成器函數的函數體纔會被執行。
>>> letters = letters_generator()
>>> type(letters)
<class 'generator'>
>>> next(letters)
'a'
>>> next(letters)
'b'
>>> next(letters)
'c'
>>> next(letters)
'd'
>>> next(letters)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
流
如果我們有一個無線長的序列需要遍歷時,怎麼辦?或者說,如果我有一個很長的序列,但是它耗費很大的內存,這個問題怎麼解決。Python的流就提供了一個解決辦法。在一個list中,所有的值都預先存放在開闢的內存中,而在流中,我們只存放了第一個值,剩下的值只有在調用的時候纔會被計算得到並存放在內存中。這樣就大大減少了內存的開銷。
class Link:
"""A linked list with a first element and the rest."""
empty = ()
def __init__(self, first, rest=empty):
assert rest is Link.empty or isinstance(rest, Link)
self.first = first
self.rest = rest
def __getitem__(self, i):
if i == 0:
return self.first
else:
return self.rest[i-1]
def __len__(self):
return 1 + len(self.rest)
class Stream:
"""A lazily computed linked list."""
class empty:
def __repr__(self):
return 'Stream.empty'
empty = empty()
def __init__(self, first, compute_rest=lambda:empty):
assert callable(compute_rest),'compute_rest must be callable.'
self.first = first
self._compute_rest = compute_rest
@property
def rest(self):
"""Return the rest of the stream, computing it if necessary."""
if self._compute_rest is not None:
self._rest = self._compute_rest()
self._compute_rest = None
return self._rest
def __repr__(self):
return 'Stream({0},<...>)'.format(repr(self.first))
r = Link(1, Link(2+3, Link(9)))
s = Stream(1, lambda:Stream(2+3, lambda:Stream(9)))
print(r.first)
print(s.first)
print(r.rest.first)
print(s.rest.first)
print(r.rest)
print(s.rest)
在上述的Stream中,self._rest初始值爲None.當使用點操作調用rest時,觸發self._rest = self._compute_rest()
,且函數compute_rest
觸發一次就被銷燬。@property
詳細解析看這裏。
下面定義一個無窮大的整數序列:
class Link:
"""A linked list with a first element and the rest."""
empty = ()
def __init__(self, first, rest=empty):
assert rest is Link.empty or isinstance(rest, Link)
self.first = first
self.rest = rest
def __getitem__(self, i):
if i == 0:
return self.first
else:
return self.rest[i-1]
def __len__(self):
return 1 + len(self.rest)
class Stream:
class empty:
def __repr__(self):
return 'Stream.empty'
empty = empty()
def __init__(self, first, compute_rest=lambda:empty):
assert callable(compute_rest),'compute_rest must be callable.'
self.first = first
self._compute_rest = compute_rest
@property
def rest(self):
if self._compute_rest is not None:
self._rest = self._compute_rest()
self._compute_rest = None
return self._rest
def __repr__(self):
return 'Stream({0},<...>)'.format(repr(self.first))
def integer_stream(first):
def compute_rest():
return integer_stream(first+1)
return Stream(first, compute_rest)
positives = integer_stream(1)
for i in range(5):
print(positives.rest.first)