Difference between revisions of "Python:Iterative Structures"

From PrattWiki
Jump to navigation Jump to search
(Created page with "Often in solving engineering problems you will want a program to run pieces of code several times with slightly - or possibly vastly - different parameters. The number of tim...")
 
(while loops)
 
(15 intermediate revisions by the same user not shown)
Line 1: Line 1:
 +
{{#css:
 +
.mw-collapsible .mw-collapsible-toggle {
 +
    float:left;
 +
    margin-left:0;
 +
    margin-right:1em;
 +
}
 +
}}
 +
 
Often in solving engineering problems you will want a program to run pieces of code several times with slightly - or possibly vastly - different parameters.  The number of times to run the code may depend on some logical expression or on the number of columns in a particular matrix.  For these, you will use iterative structures.
 
Often in solving engineering problems you will want a program to run pieces of code several times with slightly - or possibly vastly - different parameters.  The number of times to run the code may depend on some logical expression or on the number of columns in a particular matrix.  For these, you will use iterative structures.
  
Line 6: Line 14:
 
A <code>for</code> loop on the other hand has a variable that scans through the entries in some iterable item (for example a list, tuple, array, range, map, string, dictionary).  The variable takes on the 0 indexed value of the item and runs the code it controls; once that code is done, it will take the next item from the sequence.  The <code>for</code> loop will run as many times as there are items in the sequence.
 
A <code>for</code> loop on the other hand has a variable that scans through the entries in some iterable item (for example a list, tuple, array, range, map, string, dictionary).  The variable takes on the 0 indexed value of the item and runs the code it controls; once that code is done, it will take the next item from the sequence.  The <code>for</code> loop will run as many times as there are items in the sequence.
  
In both <code>for</code> and <code>while</code> loops, there are two commands that will change the behavior of the loop a bit.  If you issue the <code>continue</code> command, the loop will immediately skip to its own end as if the code block were over.  A <code>while</code> loop would then evaluate the logical expression again and re-run its code if the expression is still true; a <code>for</code> loop will grab the next item from the sequence if there is on.  The other command that changes how a loop behaves is a <code>break</command>; if a loop runs a <code>break</code> command it will skip out of the loop immediately.
+
In both <code>for</code> and <code>while</code> loops, there are two commands that will change the behavior of the loop a bit.  If you issue the <code>continue</code> command, the loop will immediately skip to its own end as if the code block were over.  A <code>while</code> loop would then evaluate the logical expression again and re-run its code if the expression is still true; a <code>for</code> loop will grab the next item from the sequence if there is on.  The other command that changes how a loop behaves is a <code>break</code>; if a loop runs a <code>break</code> command it will skip out of the loop immediately.
  
 
== Examples ==
 
== Examples ==
Line 13: Line 21:
 
You might start your code by getting an input from the user:
 
You might start your code by getting an input from the user:
 
<syntaxhighlight lang=python>
 
<syntaxhighlight lang=python>
x = input('Number in range [0,10]: ')
+
x = input('Number in range [0, 10]: ')
 
</syntaxhighlight>  
 
</syntaxhighlight>  
 
If you run this code, you will realize that Python's <code>input</code> command renders whatever you give it as a string.  To fix that, you can tell Python to re-cast it as a <code>float</code>:
 
If you run this code, you will realize that Python's <code>input</code> command renders whatever you give it as a string.  To fix that, you can tell Python to re-cast it as a <code>float</code>:
 
<syntaxhighlight lang=python>
 
<syntaxhighlight lang=python>
x = float(input('Number in range [0,10]: '))
+
x = float(input('Number in range [0, 10]: '))
 
</syntaxhighlight>  
 
</syntaxhighlight>  
This works, but it neither checks to see if the user actually entered a numerical type nor does it check if the value is in the right range.  Because you will want the user to keep entering values until something valid is entered, you will use a <code>while</code> loop to evaluate the answer and get another value:
+
This works, but it neither checks to see if the user actually entered a numerical type nor does it check if the value is in the right range.  Because you will want the user to keep entering values until something valid is entered, you will use a <code>while</code> loop to evaluate the answer and, if the value is bad, get another value:
 
<syntaxhighlight lang=python>
 
<syntaxhighlight lang=python>
x = float(input('Number in range [0,10]: '))
+
x = float(input('Number in range [0, 10]: '))
 
while x < 0 or x > 10:
 
while x < 0 or x > 10:
 
     x = float(input('Incorrect value - number in range [0, 10]: '))
 
     x = float(input('Incorrect value - number in range [0, 10]: '))
 
</syntaxhighlight>  
 
</syntaxhighlight>  
This now does exactly what you want it to do, as long as the user has given an input that can be rendered as a float.  If the user enters a non-numerical character, Python will give an error.  If you want to deal with that situation, you will need to check what the user gives as an input before trying to make it a float.
+
This now does exactly what you want it to do, as long as the user has given an input that can be rendered as a float.  If the user enters a non-numerical character, Python will give an error.  If you want to deal with that situation, you will need to check what the user gives as an input before trying to make it a float. This is complicated by the fact that Python does not currently have a great way to check if the contents of a string can represent a float.  Given that, it might be easier to use Python's <code>try</code> structure and then catch and display any exceptions.  Here's an example that takes advantage of <code>try</code>, <code>continue</code>, and <code>break</code> to first see if the string entered could be turned into a float and, if it can, if that float is in the proper range:
 +
<syntaxhighlight lang=python>
 +
x = input('Number in range [0, 10]: ')
 +
while True:
 +
    try:
 +
        x = float(x)
 +
    except Exception as oops:
 +
        print(oops)
 +
        print('"{}" contains invalid characters'.format(x))
 +
        x = input('Number in range [0, 10]: ')
 +
        continue
 +
 
 +
    if x < 0 or x > 10:
 +
        x = input('Incorrect value - number in range [0, 10]: ')
 +
    else:
 +
        break
 +
</syntaxhighlight>
 +
Note the use of <code>while True</code> here; this loop will run indefinitely on its own - the only thing that causes it to stop is if the <code>break</code> happens.
 +
 
 +
If you would like to watch the execution of the code above on PythonTutor, click [http://pythontutor.com/visualize.html#code=x%20%3D%20input%28'Number%20in%20range%20%5B0,%2010%5D%3A%20'%29%0Awhile%20True%3A%0A%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20x%20%3D%20float%28x%29%0A%20%20%20%20except%20Exception%20as%20oops%3A%0A%20%20%20%20%20%20%20%20print%28oops%29%0A%20%20%20%20%20%20%20%20print%28'%22%7B%7D%22%20contains%20invalid%20characters'.format%28x%29%29%0A%20%20%20%20%20%20%20%20x%20%3D%20input%28'Number%20in%20range%20%5B0,%2010%5D%3A%20'%29%0A%20%20%20%20%20%20%20%20continue%0A%0A%20%20%20%20if%20x%20%3C%200%20or%20x%20%3E%2010%3A%0A%20%20%20%20%20%20%20%20x%20%3D%20input%28'Incorrect%20value%20-%20number%20in%20range%20%5B0,%2010%5D%3A%20'%29%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20break&cumulative=false&heapPrimitives=nevernest&mode=edit&origin=opt-frontend.js&py=py3anaconda&rawInputLstJSON=%5B%22a%22,%2212%22,%22h%22,%226%22%5D&textReferences=false here].
 +
 
 +
=== <code>for</code> loops ===
 +
The following codes will demonstrate different ways to scan through the entries of an iterable:
 +
==== Scanning through a list (or tuple, or array)====
 +
<syntaxhighlight lang=python>
 +
for k in [3, 1, 4, 1, 5]:
 +
    print(k, end=' ')
 +
</syntaxhighlight>
 +
 
 +
<div class="toccolours mw-collapsible mw-collapsed">
 +
<div style="font-weight:bold;line-height:1.6;">Output:</div>
 +
<div class="mw-collapsible-content" style="white-space: pre;">
 +
3 1 4 1 5
 +
</div>
 +
</div>
 +
 
 +
====  Scanning through a string====
 +
<syntaxhighlight lang=python>
 +
for k in 'Hello!':
 +
    print(k)
 +
</syntaxhighlight>
 +
<div class="toccolours mw-collapsible mw-collapsed">
 +
<div style="font-weight:bold;line-height:1.6;">Output:</div>
 +
<div class="mw-collapsible-content" style="white-space: pre;">
 +
H
 +
e
 +
l
 +
l
 +
o
 +
!
 +
</div>
 +
</div>
 +
 
 +
====  Scanning through a range (or map) ====
 +
<syntaxhighlight lang=python>
 +
for k in range(3, 7):
 +
    print(k, end=' ')
 +
</syntaxhighlight>
 +
<div class="toccolours mw-collapsible mw-collapsed">
 +
<div style="font-weight:bold;line-height:1.6;">Output:</div>
 +
<div class="mw-collapsible-content" style="white-space: pre;">
 +
3 4 5 6
 +
</div>
 +
</div>
 +
 
 +
==== Scanning through a dictionary====
 +
Assume the following code has run to create a dictionary <code>d</code>:
 +
<syntaxhighlight lang=python>
 +
d = {}
 +
d[4]='hello'
 +
d['Duke']=1.234
 +
d[(20,19)] = [20, 23]
 +
</syntaxhighlight>
 +
such that <code>d</code> is now:
 +
<syntaxhighlight lang=python>
 +
{4: 'hello', 'Duke': 1.234, (20, 19): [20, 23]}
 +
</syntaxhighlight>
 +
There are four ways to scan through it:
 +
<syntaxhighlight lang=python>
 +
for k in d:
 +
    print(k)
 +
</syntaxhighlight>
 +
<div class="toccolours mw-collapsible mw-collapsed">
 +
<div style="font-weight:bold;line-height:1.6;">Output:</div>
 +
<div class="mw-collapsible-content" style="white-space: pre;">
 +
4
 +
Duke
 +
(20, 19)
 +
</div>
 +
</div>
 +
 
 +
<syntaxhighlight lang=python>
 +
for k in d.values():
 +
    print(k)
 +
</syntaxhighlight>   
 +
<div class="toccolours mw-collapsible mw-collapsed">
 +
<div style="font-weight:bold;line-height:1.6;">Output:</div>
 +
<div class="mw-collapsible-content" style="white-space: pre;">
 +
hello
 +
1.234
 +
[20, 23]
 +
</div>
 +
</div>
 +
 
 +
<syntaxhighlight lang=python>
 +
for k in d.items():
 +
    print(k)
 +
</syntaxhighlight>
 +
<div class="toccolours mw-collapsible mw-collapsed">
 +
<div style="font-weight:bold;line-height:1.6;">Output:</div>
 +
<div class="mw-collapsible-content" style="white-space: pre;">
 +
(4, 'hello')
 +
('Duke', 1.234)
 +
((20, 19), [20, 23])
 +
</div>
 +
</div>
 +
 
 +
<syntaxhighlight lang=python>
 +
for p, q in d.items():
 +
    print('p: {}, q: {}'.format(p, q))
 +
</syntaxhighlight>
 +
<div class="toccolours mw-collapsible mw-collapsed">
 +
<div style="font-weight:bold;line-height:1.6;">Output:</div>
 +
<div class="mw-collapsible-content" style="white-space: pre;">
 +
p: 4, q: hello
 +
p: Duke, q: 1.234
 +
p: (20, 19), q: [20, 23]
 +
</div>
 +
</div>
  
 +
==== Scanning through a sequence of sequences ====
 +
As noted above, the <code>for</code> loop can either take each item in a sequence and assign it to a single variable or, if the items are themselves sequences, deal out the items within those sequences to multiple variables.  The latter will only work if the number of items in the subsequence is the same as the number of variables or - and this is super fancy - you put an *arg type variable in your <code>for</code> loop.  Here are some examples:
  
== Indexing Items ==
+
===== One scanning variable with a sequence of sequences all of size N =====
While using a loop, you may want to access certain elements of matrices and vectors within that loop. To do this, you will need a variable that holds on to the index number you want to access.  There are two fundamentally different ways to create this variable: using the loop scanning variable itself as in index it appropriate, or creating an external counter.
+
<syntaxhighlight lang=python>
 +
for k in [[1, 2], [3, 'hi'], [(4, 5, 6), [7, 8, 9]]]:
 +
    print('k: {}'.format(k))
 +
</syntaxhighlight>
 +
<div class="toccolours mw-collapsible mw-collapsed">
 +
<div style="font-weight:bold;line-height:1.6;">Output:</div>
 +
<div class="mw-collapsible-content" style="white-space: pre;">
 +
k: [1, 2]
 +
k: [3, 'hi']
 +
k: [(4, 5, 6), [7, 8, 9]]
 +
</div>
 +
</div>
  
=== Scanner Variable ===
+
===== N scanning variables with a sequence of sequences all of size N =====
If you have a loop that is meant to go through a pre-determined number of iterations, and you have set up a loop counter to count the iteration you are on:
+
<syntaxhighlight lang=python>
<source lang="matlab">
+
for a, b in [[1, 2], [3, 'hi'], [(4, 5, 6), [7, 8, 9]]]:
for K=1:12
+
     print('a: {}; b: {}'.format(a, b))
     % Code
+
</syntaxhighlight>
end
+
<div class="toccolours mw-collapsible mw-collapsed">
</source>
+
<div style="font-weight:bold;line-height:1.6;">Output:</div>
you can use the scanning variable as the indexing variable. For instance, to obtain twelve different values from a user, you can use the following code:
+
<div class="mw-collapsible-content" style="white-space: pre;">
<source lang="matlab">
+
a: 1; b: 2
Temperatures = [];
+
a: 3; b: hi
for K=1:12
+
a: (4, 5, 6); b: [7, 8, 9]
    Temperatures(K) = input('Enter a temperature: ');
+
</div>
end
+
</div>
</source>
 
and the fact that K takes on the values of 1, 2, 3, etc., will work as your index variable.  The Temperatures variable will end up as a 1 x 12 matrix with the values the users gave you.
 
  
=== External Variable ===
+
===== One scanning variable with sequence of sequences all differing sizes =====
Sometimes, you will not have an integer-based scanning variable - or you may not have a scanning variable at all (example: while loops).  For those, you may have to start an external counter.  For example, if you want to store temperature inputs so long as the temperatures entered are non-negative, you could write:
+
<syntaxhighlight lang=python>
<source lang="matlab">
+
for k in [[1], [2,3], [4, 5 ,6], 'Duke', [7, 'EGR', 103]]:
NumTemps = 0;
+
    print('k: {}'.format(k))
Temperatures = []; % starts off empty
+
</syntaxhighlight>
TempInput = input('Enter a temperature (negative to stop): ');
+
<div class="toccolours mw-collapsible mw-collapsed">
while TempInput>=0
+
<div style="font-weight:bold;line-height:1.6;">Output:</div>
    NumTemps = NumTemps + 1;
+
<div class="mw-collapsible-content" style="white-space: pre;">
    Temperatures(NumTemps) = TempInput;
+
k: [1]
    TempInput = input('Enter a temperature (negative to stop): ');
+
k: [2, 3]
end
+
k: [4, 5, 6]
</source>
+
k: Duke
At the end of this code, NumTemps will be a value that indicates how many entries there are in Temperatures, and Temperatures will be a 1 x NumTemps matrix of temperature values.
+
k: [7, 'EGR', 103]
 +
</div>
 +
</div>
  
== Initializing Large Vectors ==
+
===== Multiple scanning variables including an *arg with sequence of sequences all differing sizes =====
One of the dangers in MATLAB's ability to automatically resize a vector is the amount of time it actually takes to do that.
+
<syntaxhighlight lang=python>
 +
for a, *b in [[1], [2,3], [4, 5 ,6], 'Duke', [7, 'EGR', 103]]:
 +
    print('a: {}; b: {}'.format(a, b))
 +
</syntaxhighlight>
 +
<div class="toccolours mw-collapsible mw-collapsed">
 +
<div style="font-weight:bold;line-height:1.6;">Output:</div>
 +
<div class="mw-collapsible-content" style="white-space: pre;">
 +
a: 1; b: []
 +
a: 2; b: [3]
 +
a: 4; b: [5, 6]
 +
a: D; b: ['u', 'k', 'e']
 +
a: 7; b: ['EGR', 103]
 +
</div>
 +
</div>
  
=== Iterative Resizing ===
+
Note that your sequences must have at least as many entries as the number of unstarred scanning variables and that you can only have one starred scanning variable.  It does '''not''' have to come last, however:
Consider the following:
+
<syntaxhighlight lang=python>
<source lang="matlab">
+
for a, *b, c in [['L', 'M1', 'M2', 'R'], [1, 2], [3, 4, 5, 6, 7]]:
clear
+
    print('a: {}; b: {}; c: {}'.format(a, b, c))
tic
+
</syntaxhighlight>
y0 = 0;
+
<div class="toccolours mw-collapsible mw-collapsed">
v0 = 5;
+
<div style="font-weight:bold;line-height:1.6;">Output:</div>
a  = -9.81;
+
<div class="mw-collapsible-content" style="white-space: pre;">
NP = 10;
+
a: L; b: ['M1', 'M2']; c: R
t = linspace(0, 5, NP)
+
a: 1; b: []; c: 2
for k=1:NP
+
a: 3; b: [4, 5, 6]; c: 7
  y(k) = y0 + v0*t(k) + 0.5*a*t(k).^2;
+
</div>
end
+
</div>
toc
+
First, note that each subsequence has at least two items<code>a</code> will take the first one, <code>c</code> will take the '''last''' one, and then <code>b</code> will take over whatever remains.
</source>
 
This code takes, on average, 36 microseconds to runIf NP is increased to 100, the average time to complete goes up to about 150 microseconds.  NP of 1000 increases the time to 2.25 ms.  And NP of 100000 increases the time to over 10 s!  The graph below shows, on a log scale, time to complete as a function of NP:
 
<center>
 
[[Image:NoInitPlot.png]]
 
</center>
 
  
Clearly, this becomes a major problem as the number of points increases.
+
== Indexing Items ==
 +
While using a loop, you may want to access certain elements of sequences within that loop.  To do this, you will need a variable that holds on to the index number you want to access.  There are at least three different ways to create this variable: using the loop scanning variable itself as in index, using the <code>enumerate</code>function to generate a table of index and value pairs, or creating an external counter.
  
=== Initialized ===
+
=== Scanner Variable ===
Remarkably, adding a single line completely changes the timing of the program. The following program:
+
If you have a <code>for</code> loop that is meant to go through a pre-determined number of iterations, you can set up the loop variable to keep track of what iteration you are on:
<source lang="matlab">
+
<syntaxhighlight lang="python">
clear
+
for k in range(12):
tic
+
    # Code
y0 = 0;
+
</syntaxhighlight >
v0 = 5;
+
For instance, to obtain twelve different values from a user, you can use the following code:
= -9.81;
+
<syntaxhighlight lang="python">
NP = 10;
+
temperatures = [None]*12
t = linspace(0, 5, NP)
+
for k in range(12):
y = t*0;    % here's the only thing that changed!!!
+
    temperatures[k] = float(input('Enter a temperature: '))
for k=1:NP
+
</syntaxhighlight>
  y(k) = y0 + v0*t(k) + 0.5*a*t(k).^2;
+
This uses the fact that <code>k</code> takes on the values of 0, 1, 2, 3, etc., which will work as your index variable.  The <code>temperatures</code> list will end up with the twelve values the users gave you.  Of course, in Python if you are just building a list, you can also append things to the list without worrying about the index:
end
+
<syntaxhighlight lang="python">
toc
+
temperatures = []
</source>
+
for k in range(12):
 +
    temperatures += [float(input('Enter a temperature: '))]
 +
</syntaxhighlight>
  
generates the following time vs. NP graph:
+
=== Enumerated Iterable ===
<center>
+
If you are iterating over something that cannot be used as an index - for example, the characters in a string - you can use the <code>enumerate</code> function to return an iterable that replaces each item with a tuple containing the index and value of the itemThe <code>enumerate</code> type is similar to <code>range</code> and <code>map</code> in that it does not have a good way of showing what it is actually equal to -- for that, you need to recast it as a list.  For example, assuming you have run the following code:
[[Image:InitPlot.png]]
+
<syntaxhighlight lang="python">
</center>
+
my_words = 'Go Duke!'
which indicates a reduction, by three orders of magnitude, of the run timeAnd all that was done was creating a vector y of the appropriate size '''before''' running the loop, rather than continuously changing the vector size inside the loop.
+
my_enum = enumerate(my_words)
 +
</syntaxhighlight>
 +
then
 +
<syntaxhighlight lang="python">
 +
print(my_enum)
 +
</syntaxhighlight>
 +
yields
 +
<syntaxhighlight lang="python">
 +
<enumerate object at 0x000001BF3194C2D0>
 +
</syntaxhighlight>
 +
while
 +
<syntaxhighlight lang="python">
 +
print(list(my_enum))
 +
</syntaxhighlight>
 +
yields:
 +
<syntaxhighlight lang="python">
 +
[(0, 'G'), (1, 'o'), (2, ' '), (3, 'D'), (4, 'u'), (5, 'k'), (6, 'e'), (7, '!')]
 +
</syntaxhighlight>
 +
You can now run a <code>for</code> loop on the results of the <code>enumerate</code> command; if you have two scanning variables, the first will pick up an index and the second will pick up the value:
 +
<syntaxhighlight lang="python">
 +
for idx, val in enumerate(my_words):
 +
    print('idx: {} val: {}'.format(idx, val))
 +
</syntaxhighlight>
 +
yields:
 +
<syntaxhighlight lang="python">
 +
idx: 0 val: G
 +
idx: 1 val: o
 +
idx: 2 val: 
 +
idx: 3 val: D
 +
idx: 4 val: u
 +
idx: 5 val: k
 +
idx: 6 val: e
 +
idx: 7 val: !
 +
</syntaxhighlight>
  
=== Vectorized ===
+
=== External Variable ===
Of course, the fastest version of the code uses MATLAB's ability to vectorize:
+
Sometimes, you will not have an integer-based scanning variable - or you may not have a scanning variable at all (example: <code>while</code> loops).  For those, you may have to start an external counter.  For example, if you want to store temperature inputs so long as the temperatures entered are non-negative, you could write:
<source lang="matlab">
+
<syntaxhighlight lang="python">
clear
+
num_temps = 0;
tic
+
temperatures = []
y0 = 0;
+
temp_in = float(input('Enter a temperature (negative to stop): '))
v0 = 5;
+
while temp_in >= 0:
a = -9.81;
+
    num_temps += 1
NP = 10;
+
    temperatures += [temp_in]
t = linspace(0, 5, NP)
+
    temp_in = float(input('Enter a temperature (negative to stop): '))
y = y0 + v0*t + 0.5*a*t.^2;
+
</syntaxhighlight >
toc
+
At the end of this code, <code>num_temps</code> will be a value that indicates how many entries there are in the <code>temperatures</code> list.
</source>
 
  
which generates the following time vs. NP graph:
 
<center>
 
[[Image:NoLoopPlot.png]]
 
</center>
 
  
 
== Questions ==
 
== Questions ==

Latest revision as of 01:03, 18 September 2019


Often in solving engineering problems you will want a program to run pieces of code several times with slightly - or possibly vastly - different parameters. The number of times to run the code may depend on some logical expression or on the number of columns in a particular matrix. For these, you will use iterative structures.

Introduction

There are two main iterative structures in Python: while loops and for loops. A while loops is controlled by some logical expression which is evaluated before deciding whether to run the code it controls. If the expression is true, the while loop will run the code it controls and once that code is done executing, it will reevaluate the logical expression. The loop will keep running until the logical expression is false at the time it gets evaluated.

A for loop on the other hand has a variable that scans through the entries in some iterable item (for example a list, tuple, array, range, map, string, dictionary). The variable takes on the 0 indexed value of the item and runs the code it controls; once that code is done, it will take the next item from the sequence. The for loop will run as many times as there are items in the sequence.

In both for and while loops, there are two commands that will change the behavior of the loop a bit. If you issue the continue command, the loop will immediately skip to its own end as if the code block were over. A while loop would then evaluate the logical expression again and re-run its code if the expression is still true; a for loop will grab the next item from the sequence if there is on. The other command that changes how a loop behaves is a break; if a loop runs a break command it will skip out of the loop immediately.

Examples

while loops

Imagine you want a user to enter a number between 0 and 10 inclusive; in cases where they get it wrong, you want them to try again. You might start your code by getting an input from the user:

x = input('Number in range [0, 10]: ')

If you run this code, you will realize that Python's input command renders whatever you give it as a string. To fix that, you can tell Python to re-cast it as a float:

x = float(input('Number in range [0, 10]: '))

This works, but it neither checks to see if the user actually entered a numerical type nor does it check if the value is in the right range. Because you will want the user to keep entering values until something valid is entered, you will use a while loop to evaluate the answer and, if the value is bad, get another value:

x = float(input('Number in range [0, 10]: '))
while x < 0 or x > 10:
    x = float(input('Incorrect value - number in range [0, 10]: '))

This now does exactly what you want it to do, as long as the user has given an input that can be rendered as a float. If the user enters a non-numerical character, Python will give an error. If you want to deal with that situation, you will need to check what the user gives as an input before trying to make it a float. This is complicated by the fact that Python does not currently have a great way to check if the contents of a string can represent a float. Given that, it might be easier to use Python's try structure and then catch and display any exceptions. Here's an example that takes advantage of try, continue, and break to first see if the string entered could be turned into a float and, if it can, if that float is in the proper range:

x = input('Number in range [0, 10]: ')
while True:
    try:
        x = float(x)
    except Exception as oops:
        print(oops)
        print('"{}" contains invalid characters'.format(x))
        x = input('Number in range [0, 10]: ')
        continue

    if x < 0 or x > 10:
        x = input('Incorrect value - number in range [0, 10]: ')
    else:
        break

Note the use of while True here; this loop will run indefinitely on its own - the only thing that causes it to stop is if the break happens.

If you would like to watch the execution of the code above on PythonTutor, click here.

for loops

The following codes will demonstrate different ways to scan through the entries of an iterable:

Scanning through a list (or tuple, or array)

for k in [3, 1, 4, 1, 5]:
    print(k, end=' ')
Output:

3 1 4 1 5

Scanning through a string

for k in 'Hello!':
    print(k)
Output:

H e l l o !

Scanning through a range (or map)

for k in range(3, 7):
    print(k, end=' ')
Output:

3 4 5 6

Scanning through a dictionary

Assume the following code has run to create a dictionary d:

d = {}
d[4]='hello'
d['Duke']=1.234
d[(20,19)] = [20, 23]

such that d is now:

{4: 'hello', 'Duke': 1.234, (20, 19): [20, 23]}

There are four ways to scan through it:

for k in d:
    print(k)
Output:

4 Duke (20, 19)

for k in d.values():
    print(k)
Output:

hello 1.234 [20, 23]

for k in d.items():
    print(k)
Output:

(4, 'hello') ('Duke', 1.234) ((20, 19), [20, 23])

for p, q in d.items():
    print('p: {}, q: {}'.format(p, q))
Output:

p: 4, q: hello p: Duke, q: 1.234 p: (20, 19), q: [20, 23]

Scanning through a sequence of sequences

As noted above, the for loop can either take each item in a sequence and assign it to a single variable or, if the items are themselves sequences, deal out the items within those sequences to multiple variables. The latter will only work if the number of items in the subsequence is the same as the number of variables or - and this is super fancy - you put an *arg type variable in your for loop. Here are some examples:

One scanning variable with a sequence of sequences all of size N
for k in [[1, 2], [3, 'hi'], [(4, 5, 6), [7, 8, 9]]]:
    print('k: {}'.format(k))
Output:

k: [1, 2] k: [3, 'hi'] k: [(4, 5, 6), [7, 8, 9]]

N scanning variables with a sequence of sequences all of size N
for a, b in [[1, 2], [3, 'hi'], [(4, 5, 6), [7, 8, 9]]]:
    print('a: {}; b: {}'.format(a, b))
Output:

a: 1; b: 2 a: 3; b: hi a: (4, 5, 6); b: [7, 8, 9]

One scanning variable with sequence of sequences all differing sizes
for k in [[1], [2,3], [4, 5 ,6], 'Duke', [7, 'EGR', 103]]:
    print('k: {}'.format(k))
Output:

k: [1] k: [2, 3] k: [4, 5, 6] k: Duke k: [7, 'EGR', 103]

Multiple scanning variables including an *arg with sequence of sequences all differing sizes
for a, *b in [[1], [2,3], [4, 5 ,6], 'Duke', [7, 'EGR', 103]]:
    print('a: {}; b: {}'.format(a, b))
Output:

a: 1; b: [] a: 2; b: [3] a: 4; b: [5, 6] a: D; b: ['u', 'k', 'e'] a: 7; b: ['EGR', 103]

Note that your sequences must have at least as many entries as the number of unstarred scanning variables and that you can only have one starred scanning variable. It does not have to come last, however:

for a, *b, c in [['L', 'M1', 'M2', 'R'], [1, 2], [3, 4, 5, 6, 7]]:
    print('a: {}; b: {}; c: {}'.format(a, b, c))
Output:

a: L; b: ['M1', 'M2']; c: R a: 1; b: []; c: 2 a: 3; b: [4, 5, 6]; c: 7

First, note that each subsequence has at least two items. a will take the first one, c will take the last one, and then b will take over whatever remains.

Indexing Items

While using a loop, you may want to access certain elements of sequences within that loop. To do this, you will need a variable that holds on to the index number you want to access. There are at least three different ways to create this variable: using the loop scanning variable itself as in index, using the enumeratefunction to generate a table of index and value pairs, or creating an external counter.

Scanner Variable

If you have a for loop that is meant to go through a pre-determined number of iterations, you can set up the loop variable to keep track of what iteration you are on:

for k in range(12):
    # Code

For instance, to obtain twelve different values from a user, you can use the following code:

temperatures = [None]*12
for k in range(12):
    temperatures[k] = float(input('Enter a temperature: '))

This uses the fact that k takes on the values of 0, 1, 2, 3, etc., which will work as your index variable. The temperatures list will end up with the twelve values the users gave you. Of course, in Python if you are just building a list, you can also append things to the list without worrying about the index:

temperatures = []
for k in range(12):
    temperatures += [float(input('Enter a temperature: '))]

Enumerated Iterable

If you are iterating over something that cannot be used as an index - for example, the characters in a string - you can use the enumerate function to return an iterable that replaces each item with a tuple containing the index and value of the item. The enumerate type is similar to range and map in that it does not have a good way of showing what it is actually equal to -- for that, you need to recast it as a list. For example, assuming you have run the following code:

my_words = 'Go Duke!'
my_enum = enumerate(my_words)

then

print(my_enum)

yields

<enumerate object at 0x000001BF3194C2D0>

while

print(list(my_enum))

yields:

[(0, 'G'), (1, 'o'), (2, ' '), (3, 'D'), (4, 'u'), (5, 'k'), (6, 'e'), (7, '!')]

You can now run a for loop on the results of the enumerate command; if you have two scanning variables, the first will pick up an index and the second will pick up the value:

for idx, val in enumerate(my_words):
    print('idx: {} val: {}'.format(idx, val))

yields:

idx: 0 val: G
idx: 1 val: o
idx: 2 val:  
idx: 3 val: D
idx: 4 val: u
idx: 5 val: k
idx: 6 val: e
idx: 7 val: !

External Variable

Sometimes, you will not have an integer-based scanning variable - or you may not have a scanning variable at all (example: while loops). For those, you may have to start an external counter. For example, if you want to store temperature inputs so long as the temperatures entered are non-negative, you could write:

num_temps = 0;
temperatures = []
temp_in = float(input('Enter a temperature (negative to stop): '))
while temp_in >= 0:
    num_temps += 1
    temperatures += [temp_in]
    temp_in = float(input('Enter a temperature (negative to stop): '))

At the end of this code, num_temps will be a value that indicates how many entries there are in the temperatures list.


Questions

Post your questions by editing the discussion page of this article. Edit the page, then scroll to the bottom and add a question by putting in the characters *{{Q}}, followed by your question and finally your signature (with four tildes, i.e. ~~~~). Using the {{Q}} will automatically put the page in the category of pages with questions - other editors hoping to help out can then go to that category page to see where the questions are. See the page for Template:Q for details and examples.

External Links

References