A loop is a section of code that repeats an action. Remember, the power of scripting (and computing in general) is the ability to quickly repeat a task that might be time-consuming or error-prone for a human. Looping is how you repeat tasks with code; whether its reading a file, searching for a value, or performing the same action on each item in a list.
A for loop does something with each item in a list. Type this in the PythonWin Interactive Window to see how a simple for loop works:
>>> for name in ["Carter", "Reagan", "Bush"]: print (name + " was a U.S. president.")
After typing this, you'll have to hit Enter twice in a row to tell PythonWin that you are done working on the loop and that the loop should be executed. You should see:
Carter was a U.S. president Reagan was a U.S. president Bush was a U.S. president
Notice a couple of important things about the loop above. First, you declared a new variable, "name," to represent each item in the list as you iterated through. This is okay to do; in fact, it's expected that you'll do this at the beginning of the for loop.
for Loops can also work with lists of numbers. Try this one in the Interactive Window:
>>> x = 2 >>> multipliers = [1,2,3,4] >>> for num in multipliers: print (x * num) 2 4 6 8
In the loop above, you multiplied each item in the list by 2. Notice that you can set up your list before you start coding the loop.
You could have also done the following with the same result:
>>> multipliers = [1,2,3,4] >>> for num in multipliers: x = 2 print (x * num)
The above code, however, is less efficient than what we did initially. Can you see why? This time, you are declaring and setting the variable x=2 inside the loop. The Python interpreter will now have to read and execute that line of code four times instead of one. You might think this is a trivial amount of work, but if your list contained thousands or millions of items, the difference in execution time would become noticeable. Declaring and setting variables outside a loop, whenever possible, is a best practice in programming.
While we're on the subject, what would you do if you wanted to multiply 2 by every number from 1 to 1000? It would definitely be too much typing to manually set up a multipliers list as in the previous example. In this case, you can use Python's built-in range function. Try this:
>>> x = 2 >>> for num in range(1,1001): print (x * num)
The range function is your way of telling Python, "Start here and stop there." We used 1001 because the loop stops one item before the function's second argument (the arguments are the values you put in parentheses to tell the function how to run). If you need the function to multiply by 0 at the beginning as well, you could even get away with using one argument:
>>> x = 2 >>> for num in range(1001): print (x * num)
The range function has many interesting uses which are detailed in this section's reading assignment in Zandbergen.
A while loop executes until some condition is met. Here's how to code our example above using a while loop:
>>> x = 0 >>> while x < 1001: ... print (x * 2) ... x += 1
while loops often involve the use of some counter that keeps track of how many times the loop has run. Sometimes you'll perform operations with the counter. For example, in the above loop, x was the counter, and we also multiplied the counter by 2 each time during the loop. To increment the counter we used x += 1 which is shorthand for x = x + 1, or "add one to x".
Some situations call for putting one loop inside another, a practice called nesting. Nested loops could help you print every card in a deck (minus the Jokers):
>>> suits = ['Spades', 'Clubs', 'Diamonds', 'Hearts'] >>> values = ['Ace', 2, 3, 4, 5, 6, 7, 8, 9, 10, 'Jack', 'Queen', 'King'] >>> for suit in suits: for value in values: print (str(value) + " of " + str(suit))
In the above example, you start with a suit, then loop through each value in the suit, printing out the card name. When you've reached the end of the list of values, you jump out of the nested loop and go back to the first loop to get the next suit. Then you loop through all values in the second suit and print the card names. This process continues until all the suits and values have been looped through.
Looping in GIS models
You will use looping repeatedly (makes sense!) as you write GIS scripts in Python. Often, you'll need to iterate through every row in a table, every field in a table, or every feature class in a folder or a geodatabase. You might even need to loop through the vertices of a geographic feature.
You saw above that loops work particularly well with lists. arcpy has some methods that can help you create lists. Here's an example you can try that uses arcpy.ListFeatureClasses(). First, manually create a new folder C:\WCGIS\Geog485\Lesson2\PracticeData. Then copy the code below into a new script in PythonWin and run the script. The script copies all the data in your Lesson1 folder into the new Lesson2\PracticeData folder you just created.
# Copies all feature classes from one folder to another import arcpy try: arcpy.env.workspace = "C:/WCGIS/Geog485/Lesson1" # List the feature classes in the Lesson 1 folder fcList = arcpy.ListFeatureClasses() # Loop through the list and copy the feature classes to the Lesson 2 PracticeData folder for featureClass in fcList: arcpy.CopyFeatures_management(featureClass, "C:/WCGIS/Geog485/Lesson2/PracticeData/" + featureClass) except: print ("Script failed to complete") print (arcpy.GetMessages(2))
Notice above that once you have a Python list of feature classes (fcList), it's very easy to set up the loop condition (for featureClass in fcList:).
Another common operation in GIS scripts is looping through tables. In fact, the arcpy module contains some special objects called cursors that help you do this. Here's a short script showing how a cursor can loop through each row in a feature class and print the name. We'll cover cursors in detail in the next lesson, so don't worry if some of this code looks confusing right now. The important thing is to notice how a loop is used to iterate through each record:
import arcpy inTable = "C:/WCGIS/Geog485/Lesson2/CityBoundaries.shp" inField = "NAME" rows = arcpy.SearchCursor(inTable) #This loop goes through each row in the table # and gets a requested field value for row in rows: currentCity = row.getValue(inField) print (currentCity)
In the above example, a search cursor named rows retrieves records from the table. The for loop makes it possible to perform an action on each individual record.
ArcGIS Help reading
Read the following in the ArcGIS Desktop Help: