Search code examples
pythonfunctionvariablesscopeglobal-variables

How to access a local variable generated inside a "while True: try/break" loop after exiting it?


I wrote a module that takes all TIFF images in a directory, averages over all frames in each image file, and saves the averaged images to an automatically generated subdirectory specified by outputPath:

def average_tiff_frames(inputPath):
    '''
    This function opens all TIFF image files in a directory, averages over all frames within each TIFF file,
    and saves the averaged images to a subdirectory.
    
    Parameters
    ----------
    inputPath : string
        Absolute path to the raw TIFF files
    '''
    import datetime
    import os
    
    import numpy as np

    from PIL import Image
    
    
    # Read image file names, create output folder
    while True:
        try:
            inputPath = os.path.join(inputPath, '')    # Add trailing slash or backslash to the input path if missing
            filenames = [filename for filename in os.listdir(inputPath)
                            if filename.endswith(('.tif', '.TIF', '.tiff', '.TIFF'))
                            and not filename.endswith(('_avg.tif'))]
            outputPath = os.path.join(inputPath, datetime.datetime.now().strftime('%Y%m%dT%H%M%S'), '')
            os.mkdir(outputPath)
            break
        except FileNotFoundError:
            print('TIFF file not found - or - frames in TIFF file already averaged (file name ends with "_avg.tif")')

    # Open image files, average over all frames, save averaged image files
    for filename in filenames:
        img = Image.open(inputPath + filename)

        width, height = img.size
        NFrames = img.n_frames

        imgArray = np.zeros((height, width))    # Ordering of axes: img.size returns (width, height), np.zeros takes (rows, columns)
        for i in range(NFrames):
            img.seek(i)
            imgArray += np.array(img)
            i += 1
        imgArrayAverage = imgArray / NFrames

        imgAverage = Image.fromarray(imgArrayAverage)
        imgAverage.save(outputPath + filename.rsplit('.')[0] + '_avg' + '.tif')

        img.close()

    return outputPath
    print('Averaged TIFF images have been saved to ' + outputPath + '. The output path is returned as a string to the variable "outputPath".')

After executing the module, I want to have outputPath (i.e. the string assigned to it) available for further steps. However, when doing

average_tiff_frames(inputPath)
print(outputPath)

I get the following error:

---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-5-99d0a947275c> in <module>()
      1 inputPath = '/home/user/Desktop/data/'
      2 average_tiff_frames(inputPath)
----> 3 print(outputPath)

NameError: name 'outputPath' is not defined

What is the problem in here?

My first thought was that outputPath is local to the while True: try loop and gets destroyed after the break, so I instantiated an empty string outputPath = '' right before the loop, but it didn't help.


Solution

  • You're not trying to access the variable outside the loop, you're trying to access it outisde the method entirely. The method returns the value you're looking for, so set that value to a variable:

    outputPath = average_tiff_frames(inputPath)
    
    print(outputPath)
    

    Or just print it directly:

    print(average_tiff_frames(inputPath))