I recently started learning Python, and the concept of for loops is still a little confusing for me. I understand that it generally follows the format for x in y
As you say, a for
loop iterates through the elements of a list. The list can contain anything you like, so you can construct a list beforehand that contains each step.
A for
loop can also iterate over a "generator", which is a small piece of code instead of an actual list. In Python, range()
is actually a generator (in Python 2.x though, range()
returned a list while xrange()
was the generator).
For example:
def doubler(x):
while True:
yield x
x *= 2
for i in doubler(1):
print i
The above for
loop will print
1
2
4
8
and so on, until you press Ctrl+C.
Just for an alternative, how about generalizing the iterate/increment operation to a lambda function so you can do something like this:
for i in seq(1, 9, lambda x: x*2):
print i
...
1
2
4
8
Where seq
is defined below:
#!/bin/python
from timeit import timeit
def seq(a, b, f):
x = a;
while x < b:
yield x
x = f(x)
def testSeq():
l = tuple(seq(1, 100000000, lambda x: x*2))
#print l
def testGen():
l = tuple((2**x for x in range(27)))
#print l
testSeq();
testGen();
print "seq", timeit('testSeq()', 'from __main__ import testSeq', number = 1000000)
print "gen", timeit('testGen()', 'from __main__ import testGen', number = 1000000)
The difference in performance isn't that much:
seq 7.98655080795
gen 6.19856786728
[EDIT]
To support reverse iteration and with a default argument...
def seq(a, b, f = None):
x = a;
if b > a:
if f == None:
f = lambda x: x+1
while x < b:
yield x
x = f(x)
else:
if f == None:
f = lambda x: x-1
while x > b:
yield x
x = f(x)
for i in seq(8, 0, lambda x: x/2):
print i
Note: This behaves differently to range
/xrange
in which the direction <
/>
test is chosen by the iterator sign, rather than the difference between start and end values.
Bear in mind that the 'list' part of the Python can be any iterable sequence.
Examples:
A string:
for c in 'abcdefg':
# deal with the string on a character by character basis...
A file:
with open('somefile','r') as f:
for line in f:
# deal with the file line by line
A dictionary:
d={1:'one',2:'two',3:'three'}
for key, value in d.items():
# deal with the key:value pairs from a dict
A slice of a list:
l=range(100)
for e in l[10:20:2]:
# ever other element between 10 and 20 in l
etc etc etc etc
So it really is a lot deeper than 'just some list'
As others have stated, just set the iterable to be what you want it to be for your example questions:
for e in (i*i for i in range(10)):
# the squares of the sequence 0-9...
l=[1,5,10,15]
for i in (i*2 for i in l):
# the list l as a sequence * 2...
You can use a generator expression to do this efficiently and with little excess code:
for i in (2**x for x in range(10)): #In Python 2.x, use `xrange()`.
...
Generator expressions work just like defining a manual generator (as in Greg Hewgill's answer), with a syntax similar to a list comprehension. They are evaluated lazily - meaning that they don't generate a list at the start of the operation, which can cause much better performance on large iterables.
So this generator works by waiting until it is asked for a value, then asking range(10)
for a value, doubling that value, and passing it back to the for
loop. It does this repeatedly until the range()
generator yields no more values.
You will want to use list comprehensions for this
print [x**2 for x in xrange(10)] # X to the 2nd power.
and
print [x**x for x in xrange(10)] # X to the Xth power.
The list comprehension syntax is a follows:
[EXPRESSION for VARIABLE in ITERABLE if CONDITION]
Under the hood, it acts similar to the map and filter function:
def f(VARIABLE): return EXPRESSION
def c(VARIABLE): return CONDITION
filter(c, map(f, ITERABLE))
Example given:
def square(x): return x**2
print map(square, xrange(10))
and
def hypercube(x): return x**x
print map(hypercube, xrange(10))
Which can be used as alternative approach if you don't like list comprehensions. You could as well use a for loop, but that would step away from being Python idiomatic...