itertools.count 和 itertools.islice 有什么意义?
What is the point of itertools.count and itertools.islice?
我看过在线课程,他们有如下示例:
from itertools import count
# creates a count iterator object
iterator =(count(start = 0, step = 2))
# prints an even list of integers
print("Even list:",
list(next(iterator) for _ in range(5)))
...您可以使用 range
或 np.arange
编写。这是另一个例子:
# list containing some strings
my_list =["x", "y", "z"]
# count spits out integers for
# each value in my list
for i in zip(count(start = 1, step = 1), my_list):
print(i)
... 基本上就是 enumerate
。所以我的问题是:你能举例说明 itertools.count
和 itertools.islice
使用 range
无法完成(或必须更笨拙地完成)吗?
如果您想节省内存使用量,您可以在 python 中使用 generators,或者库可以使用生成器。切片生成器 islice
很方便。 count
比 enumerate
更灵活。
一个非常简单的生成器
import itertools as it
import random
random.seed(42)
def fib():
x, y = 0, 1
while True:
yield x
x, y = y, x + y
x = random.randint(5, 40)
start, step = 2.5, .1
使用带浮点数的 count
和 islice
来分割生成器。
for c, i in zip(it.count(start, step), it.islice(fib(), x, x+5)):
print(f'{c:.1f}', i)
输出
2.5 144
2.6 233
2.7 377
2.8 610
2.9 987
没有itertools
使用生成器并不太难,但确实需要更多的努力。所以它仍然是个人选择的风格。有更多方法可以实现这一点,但我尽量做到像 itertools
一样富有表现力,并且尽量不笨拙。
g = fib()
for c in range(x+5):
n = next(g)
if c >= x:
print(f'{start + (c-x)*step:.1f}', n)
输出
2.5 144
2.6 233
2.7 377
2.8 610
2.9 987
这里是偶尔使用 count
实例的情况,而不是立即在一个循环中使用。
class Foo:
_x = count() # Infinite supply of unique integer values
def __init__(self):
self._id = f'Foo #{next(self._x)}'
下面是使用islice
来防止O(n)内存使用的情况:
def is_sorted(some_list):
return all(i <= j for i, j in zip(some_list, islice(some_list, 1, None)))
如果你把它写成
def is_sorted(some_list):
return all(i <= j for i, j in zip(some_list, some_list[1:]))
在测试第一对之前,您将不得不制作几乎完整的 some_list
副本,这对于像 [2, 1] + [3] * 10000
.
这样的大列表来说是一种巨大的浪费
两者都不是 必需的,因为每一个都可以简单地定义:
def count(start=0, step=1):
while True:
yield start
start += step
# A more accurate translation would be more complicated than necessary for our purposes here.
# The real version would have to be able to handle stop=None
# and choose 1 and -1 as default values for step, depending
# on whether stop is less than or greater than start.
def islice(itr, start, stop, step):
for _ in range(start):
next(itr)
while start < stop:
yield next(itr)
start += step
我看过在线课程,他们有如下示例:
from itertools import count
# creates a count iterator object
iterator =(count(start = 0, step = 2))
# prints an even list of integers
print("Even list:",
list(next(iterator) for _ in range(5)))
...您可以使用 range
或 np.arange
编写。这是另一个例子:
# list containing some strings
my_list =["x", "y", "z"]
# count spits out integers for
# each value in my list
for i in zip(count(start = 1, step = 1), my_list):
print(i)
... 基本上就是 enumerate
。所以我的问题是:你能举例说明 itertools.count
和 itertools.islice
使用 range
无法完成(或必须更笨拙地完成)吗?
如果您想节省内存使用量,您可以在 python 中使用 generators,或者库可以使用生成器。切片生成器 islice
很方便。 count
比 enumerate
更灵活。
一个非常简单的生成器
import itertools as it
import random
random.seed(42)
def fib():
x, y = 0, 1
while True:
yield x
x, y = y, x + y
x = random.randint(5, 40)
start, step = 2.5, .1
使用带浮点数的 count
和 islice
来分割生成器。
for c, i in zip(it.count(start, step), it.islice(fib(), x, x+5)):
print(f'{c:.1f}', i)
输出
2.5 144
2.6 233
2.7 377
2.8 610
2.9 987
没有itertools
使用生成器并不太难,但确实需要更多的努力。所以它仍然是个人选择的风格。有更多方法可以实现这一点,但我尽量做到像 itertools
一样富有表现力,并且尽量不笨拙。
g = fib()
for c in range(x+5):
n = next(g)
if c >= x:
print(f'{start + (c-x)*step:.1f}', n)
输出
2.5 144
2.6 233
2.7 377
2.8 610
2.9 987
这里是偶尔使用 count
实例的情况,而不是立即在一个循环中使用。
class Foo:
_x = count() # Infinite supply of unique integer values
def __init__(self):
self._id = f'Foo #{next(self._x)}'
下面是使用islice
来防止O(n)内存使用的情况:
def is_sorted(some_list):
return all(i <= j for i, j in zip(some_list, islice(some_list, 1, None)))
如果你把它写成
def is_sorted(some_list):
return all(i <= j for i, j in zip(some_list, some_list[1:]))
在测试第一对之前,您将不得不制作几乎完整的 some_list
副本,这对于像 [2, 1] + [3] * 10000
.
两者都不是 必需的,因为每一个都可以简单地定义:
def count(start=0, step=1):
while True:
yield start
start += step
# A more accurate translation would be more complicated than necessary for our purposes here.
# The real version would have to be able to handle stop=None
# and choose 1 and -1 as default values for step, depending
# on whether stop is less than or greater than start.
def islice(itr, start, stop, step):
for _ in range(start):
next(itr)
while start < stop:
yield next(itr)
start += step