Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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
    ...
like image 659
Juha Avatar asked Apr 25 '12 14:04

Juha


People also ask

What is a place that is recommended for you to nearly always use a try-except block?

The reason to use try/except is when you have a code block to execute that will sometimes run correctly and sometimes not, depending on conditions you can't foresee at the time you're writing the code.

What is the purpose of a try-except statement?

The try-except statement is a Microsoft extension to the C language that enables applications to gain control of a program when events that normally terminate execution occur. Such events are called exceptions, and the mechanism that deals with exceptions is called structured exception handling.

How do you use try-except in Python?

The try and except Block: Handling Exceptions. The try and except block in Python is used to catch and handle exceptions. Python executes code following the try statement as a “normal” part of the program. The code that follows the except statement is the program's response to any exceptions in the preceding try clause ...

Which statement is used at the end of a try-except block to ensure that some code will run even if there are errors?

Use an else clause right after the try-except block. The else clause will get hit only if no exception is thrown. The else statement should always precede the except blocks. In else blocks, you can add code which you wish to run when no errors occurred.


2 Answers

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
like image 100
Niklas B. Avatar answered Sep 30 '22 14:09

Niklas B.


In your specific case, a regular expression will get rid of the need to do these try-except blocks. Something like this might catch your cases:

>>> import re
>>> re.match('.*(S0001|_0_)([0-9]+)\..*$', 'something_0_1234.tiff').groups()
('_0_', '1234')
>>> re.match('.*(S0001|_0_)([0-9]+)\..*$', 'somethingS00011234.tif').groups()
('S0001', '1234')
>>> re.match('.*(S0001|_0_)([0-9]+)\..*$', 'somethingS00011234.tiff').groups()
('S0001', '1234')

For your question about the serial try-except blocks, Niklas B.'s answer is obviously a great one.

Edit: What you are doing is called pattern matching, so why not use a pattern matching library? If the regex string is bothering you, there are cleaner ways to do it:

import re
matchers = []
sep = ['S0001', '_0_']
matchers.append(re.compile('^.*(' + '|'.join(sep) + ')(\d+)\..*$'))
matchers.append(some_other_regex_for_other_cases)

for matcher in matchers:
    match = matcher.match(yourstring)
    if match:
        print match.groups()[-1]

Another, more generic way which is compatible with custom functions:

import re
matchers = []
simple_sep = ['S0001', '_0_']
simple_re = re.compile('^.*(' + '|'.join(sep) + ')(\d+)\..*$')
def simple_matcher(s):
    m = simple_re.match(s)
    if m:
        return m.groups()[-1]

def other_matcher(s):
    if s[3:].isdigit():
        return s[3:]

matchers.append(simple_matcher)
matchers.append(other_matcher)

for matcher in matchers:
    match = matcher('yourstring')
    if match:
        print int(match)
like image 36
mensi Avatar answered Sep 30 '22 14:09

mensi