I can print a local variable but not return it (python 2.7)
<p>EDIT:
Adding in </p>

<pre><code>upperline = []
lowerline = []
</code></pre>

<p>above the <code>for</code> loop seems to allow the function to be called once as expected, but not more than once. If called a second time the following error will be thrown:</p>

<pre><code>transitenergy = (float(upperline[1]) - float(lowerline[1]))
IndexError: list index out of range
</code></pre>

<p>If instead </p>

<pre><code>upperline = [1,2]
lowerline = [4,5]
</code></pre>

<p>is added above the <code>for</code> loop, the function returns the expected value the first time, and then -3 every other time.</p>

<hr>

<p>I am having a problem with a <code>for</code> loop seemingly being unable to retain variables when trying to return these variables, even though I can print the variables.
If I define the function as follows, when it is called , the <code>transitenergy</code> will be printed to the console, and then the following error will be thrown:</p>

<pre><code>transitenergy = (float(upperline[1]) - float(lowerline[1]))

UnboundLocalError: local variable 'upperline' referenced before assignment"
</code></pre>

<p>&nbsp;</p>

<pre><code>def crossreference(datafile, lookuppointers):
    pointers = [(int(lookuppointers[0]) - 1), (int(lookuppointers[1]) - 1)]
    lowerpointer = min(pointers)
    upperpointer = max(pointers)
    for i, line in enumerate(datafile):
        if i == lowerpointer:
            lowerline = filter(lambda a: a!= '\t',filterstring(line))
        elif i == upperpointer:
            upperline = filter(lambda a: a!= '\t',filterstring(line))
            break
    transitenergy = (float(upperline[1]) - float(lowerline[1]))]
    print transitenergy
    return transitenergy
</code></pre>

<p>I have also tried moving the return statement inside the loop i.e.</p>

<pre><code>...
elif i == upperpointer:
    upperline = filter(lambda a: a!= '\t',filterstring(line))
    transitenergy = (float(upperline[1]) - float(lowerline[1]))
    return transitenergy
</code></pre>

<p>or adding the return to a further <code>elif</code> branch i.e.</p>

<pre><code>...
elif i == upperpointer:
    upperline = filter(lambda a: a!= '\t',filterstring(line))
elif i &gt; upperpointer:
    transitenergy = (float(upperline[1]) - float(lowerline[1]))
    return transitenergy
</code></pre>

<p>but both of these just return a <code>NoneType</code> when the function is called and throws <code>TypeError: bad operand type for abs(): NoneType</code> when I try to call <code>abs()</code> on it (as expected of a <code>NoneType</code>). </p>

<p>The interesting part here, is if a print statement after defining the local <code>transitenergy</code> variable, in any of the trials I have described, calling the function prints <code>transitenergy</code> without a problem, and then throws the errors.</p>

<p>I should mention that the datafile used in the <code>datafile</code> argument are very large files (on the order of 100+Mb) where each line has the structure:</p>

<pre><code>"           [line number+1]     [float]      ...." 
</code></pre>

<p>(there are more numbers after this in the string but they are not relevant to the task)</p>

<p>The <code>lookuppointers</code> argument are lists of the following structure:</p>

<pre><code>[int, int, ...]
</code></pre>

<p>The integers are not ordered (hence the <code>min</code> and <code>max</code>) and refer to a [line number +1] of the <code>datafile</code></p>

<p>The line:</p>

<pre><code>filter(lambda a: a!= '\t',filterstring(line))
</code></pre>

<p>Is because I am iterating over a list of many of these files, and although they usually are in the correct format, and sometimes they will have a <code>\t</code> at the beginning.</p>

<p>The <code>filterstring</code> function is defined as:</p>

<pre><code>def filterstring(string):
    return filter(lambda a:a!='',string.split(" "))
</code></pre>

<p>to turn the line in the <code>datafile</code> into a list of strings.</p>

<p>The question is how can I return the <code>transitenergy</code> variable as it is printed.</p>

<p>If there is another way that I can perform this type of cross referencing without having the whole <code>datafile</code> in memory then that would work also.</p>

<p>The solution lies in in the fact that the datafile was kept open. Adding the line <code>datafile.seek(0)</code> to the function i.e.</p>

<pre><code>def crossreference(datafile, lookuppointers):
    pointers = [(int(lookuppointers[0]) - 1), (int(lookuppointers[1]) - 1)]
    lowerpointer = min(pointers)
    upperpointer = max(pointers)
    datafile.seek(0)
    for i, line in enumerate(datafile):
        if i == lowerpointer:
            lowerline = filter(lambda a: a!= '\t',filterstring(line))
        elif i == upperpointer:
            upperline = filter(lambda a: a!= '\t',filterstring(line))
            transitenergy = (float(upperline[1]) - float(lowerline[1]))
            return transitenergy
</code></pre>

<p>Caused the file to be read from the beginning each time the function was called, as opposed to what was happening before where the file was being read from the last place it was read from.</p>

python python-2.7 function for-loop