Search code examples
pythonnestedtry-catchfactory-patternsequential

What is the pythonic way to implement sequential try-excepts?


I have to parse some numbers from file names that have no common logic. I want to use the python way of "try and thou shall be forgiven", or try-except structure. Now I have to add more than two cases. What is the correct way of doing this? I am now thinking either nested try's or try-except-pass, try-except-pass,... Which one would be better or something else? Factory method perhaps (how?)?

This has to be easily expandable in the future as there will be much more cases.

Below is what I want (does not work because only one exeption per try can exist):

try:
    # first try
    imNo = int(imBN.split('S0001')[-1].replace('.tif',''))
except:
    # second try
    imNo = int(imBN.split('S0001')[-1].replace('.tiff',''))
except:
    # final try
    imNo = int(imBN.split('_0_')[-1].replace('.tif',''))

Edit:

Wow, thanks for the answers, but no pattern matching please. My bad, put "some common logic" at the beginning (now changed to "no common logic", sorry about that). In the cases above patterns are pretty similar... let me add something completely different to make the point.

except:
    if imBN.find('first') > 0: imNo = 1
    if imBN.find('second') > 0: imNo = 2
    if imBN.find('third') > 0: imNo = 3
    ...

Solution

  • You can extract the common structure and make a list of possible parameters:

    tries = [
        ('S0001', '.tif'),
        ('S0001', '.tiff'),
        ('_0_', '.tif'),
    ]
    
    for sep, subst in tries:
        num = imBN.split(sep)[-1].replace(subst, '')
        try:
            imNo = int(num)
            break
        except ValueError:
            pass
    else:
        raise ValueError, "String doesn't match any of the possible patterns"
    

    Update in reaction to question edit

    This technique can easily be adapted to arbitrary expressions by making use of lambdas:

    def custom_func(imBN):
        if 'first' in imBN: return 1
        if 'second' in imBN: return 2
    
    tries = [
        lambda: int(imBN.split('S0001')[-1].replace('.tif','')),
        lambda: int(imBN.split('S0001')[-1].replace('.tiff','')),
        lambda: int(imBN.split('_0_')[-1].replace('.tif','')),
        lambda: custom_func(imBN),
    ]
    
    for expr in tries:
        try:
            result = expr()
            break
        except:
            pass
    else:
        # error