[Tutor] Beginner's question: Looping through variable & list simultaneously

Steven D'Aprano steve at pearwood.info
Tue Dec 3 16:51:52 CET 2013


On Tue, Dec 03, 2013 at 01:55:31PM +0100, Rafael Knuth wrote:
> Hej there,
> 
> I am writing a little throw away program in order to better understand
> how I can loop through a variable and a list at the same time.

I'm afraid you may be slightly confused as to what is going on with 
for-loops in Python. For-loops in Python *always*, without exception, 
loop over the items of a "list".

I've put list in quotation marks here because it's not necessarily an 
*actual* list, but it can be anything which is list-like. But the 
important thing is that Python doesn't have anything like the C-style 
for loops:

for ( x = 0; x < 10; x++ ) {
  something;
  }


or Pascal:

for i := 1 to 100 do
  something;


So what is going on when you use a for-loop in Python? 

Python for-loops are what some other languages call a "for-each loop", 
it expects a collection or sequence of values, and then sets the loop 
variable to each value in turn. So we can loop over a list:

for item in [2, "three", 23]:
    print(item)

will print each of 2, "three" and 23. This is equivalent to this 
pseudo-code:

  sequence = [2, "three", 23]
  get the first item of sequence  # in this case, 2
  set loop variable "item" equal to that item
  execute the body of the loop
  get the second item of sequence  # "three"
  set loop variable "item" to that item
  execute the body of the loop

and so on, until you run out of items.

It isn't just lists that this process works on. It works with strings:

for char in "Hello":
    print(char)

will print "H", "e", "l", "l", and "o".

It works with tuples, sets, dicts, and many other objects. It even works 
with range objects.

What is a range object? Range objects are a special sort of object which 
are designed to provide a series of integer values. In Python 2, there 
are two related functions:

    range, which actually returns a list

    xrange, which is like range except it generates values lazily, 
    only when requested.

So in Python 2, range(900000) creates a list containing the first 900 
thousand integers. xrange(900000) creates a special object which 
prepares to create those 900 thousand integers, but doesn't actually do 
so until needed. So xrange is more memory-efficient in Python 2.

In Python 3, xrange has been renamed to just plain old "range", and the 
old range that creates a list up front is gone.

But the important thing to learn from this is that range (or xrange) is 
just an object, a sequence object like lists and tuples and strings and 
all sorts of other things. You can't do this in Pascal:

values := 1 to 10;
for i := values do
  something;


but in Python we can:

values = list(range(10))
values.append(20)
values.append(30)
for value in values:
    print(value)


prints 0, 1, 2, through 9, 20, 30.

The values in the sequence can be anything, including tuples:

py> for item in [(1, 2), (3, 4), (5, 6)]:
...     x = item[0]
...     y = item[1]
...     print(x+y)
...
3
7
11

There's a shorter way to write that:

py> for x,y in [(1, 2), (3, 4), (5, 6)]:
...     print(x+y)
...
3
7
11



You don't have to write out the pairs values by hand. Python comes with 
some functions to join two or more sets of values into one. The most 
important is the zip() function, so called because it "zips up" two 
sequences into a single sequence. So we can do this:

py> for x, y in zip([1, 3, 5], [2, 4, 6]):
...     print(x+y)
3
7
11

In this case, zip() takes the two lists and returns a single sequence of 
values (1,2), (3,4) and (5,6).

The zip function works with any number of sequences:

zip([1, 2, 3], "abc", "XYZ", (4, 5, 6), range(50, 100))

will give:

(1, "a", "X", 4, 50)
(2, "b", "Y", 5, 51)
(3, "c", "Z", 6, 52)


Here's a modification to your earlier code using zip:


PopularCountries = ["Brazil", "China", "France", "India", "Vietnam"]
Backpackers = 1000000
msg = "In %d there were %d backpackers worldwide and their most popular country was %s."
for year, country in zip(range(2009, 2014), PopularCountries):
    Backpackers = Backpackers*1.15
    print(msg % (year, Backpackers, country))




Hope this helps!



-- 
Steven


More information about the Tutor mailing list