For loops (novice)

青春壹個敷衍的年華 提交于 2019-12-01 16:49:51

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.

Gareth Latty

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.

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 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...

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!