Reputation: 69924
Is there a straight-forward expression that can produce an infinite iterator?
This is a purely theoretical question. No need for a "practical" answer here :)
For example, it is easy to use a generator expression to make a finite iterator:
my_gen = (0 for i in range(42))
However, to make an infinite one I need to "pollute" my namespace with a bogus function:
def _my_gen():
while True:
yield 0
my_gen = _my_gen()
Doing things in a separate file and import
-ing later doesn't count.
I also know that itertools.repeat
does exactly this. I'm curious if there is a one-liner solution without that.
Upvotes: 161
Views: 103071
Reputation: 304117
Your OS may provide something that can be used as an infinite generator. Eg on linux
for i in (0 for x in open('/dev/urandom', 'rb')):
print(i)
obviously this is not as efficient as
for i in __import__('itertools').repeat(0):
print(i)
Upvotes: 10
Reputation: 9064
You can iterate over a callable returning a constant always different than iter()
's sentinel
g1 = iter(lambda: 0, 1)
Upvotes: 27
Reputation: 123612
itertools
provides three infinite iterators:
count(start=0, step=1)
: 0, 1, 2, 3, 4, ...
cycle(p)
: p[0], p[1], ..., p[-1], p[0], ...
repeat(x, times=∞)
: x, x, x, x, ...
I don't know of any others in the standard library.
Since you asked for a one-liner:
__import__("itertools").count()
Upvotes: 295
Reputation: 7507
Quite ugly and crazy (very funny however), but you can build your own iterator from an expression by using some tricks (without "polluting" your namespace as required):
{ print("Hello world") for _ in
(lambda o: setattr(o, '__iter__', lambda x:x)
or setattr(o, '__next__', lambda x:True)
or o)
(type("EvilIterator", (object,), {}))() }
Upvotes: 7
Reputation: 41486
for x in iter(int, 1): pass
iter
= zero-argument callable + sentinel valueint()
always returns 0
Therefore, iter(int, 1)
is an infinite iterator. There are obviously a huge number of variations on this particular theme (especially once you add lambda
into the mix). One variant of particular note is iter(f, object())
, as using a freshly created object as the sentinel value almost guarantees an infinite iterator regardless of the callable used as the first argument.
Upvotes: 177
Reputation: 9091
Maybe you could use decorators like this for example:
def generator(first):
def wrap(func):
def seq():
x = first
while True:
yield x
x = func(x)
return seq
return wrap
Usage (1):
@generator(0)
def blah(x):
return x + 1
for i in blah():
print i
Usage (2)
for i in generator(0)(lambda x: x + 1)():
print i
I think it could be further improved to get rid of those ugly ()
. However it depends on the complexity of the sequence that you wish to be able to create. Generally speaking if your sequence can be expressed using functions, than all the complexity and syntactic sugar of generators can be hidden inside a decorator or a decorator-like function.
Upvotes: 2
Reputation:
None that doesn't internally use another infinite iterator defined as a class/function/generator (not -expression, a function with yield
). A generator expression always draws from anoter iterable and does nothing but filtering and mapping its items. You can't go from finite items to infinite ones with only map
and filter
, you need while
(or a for
that doesn't terminate, which is exactly what we can't have using only for
and finite iterators).
Trivia: PEP 3142 is superficially similar, but upon closer inspection it seems that it still requires the for
clause (so no (0 while True)
for you), i.e. only provides a shortcut for itertools.takewhile
.
Upvotes: 9