实现顺序try-excepts的pythonic方法是什么?

时间:2012-04-25 14:27:24

标签: python nested try-catch factory-pattern sequential

我必须从没有通用逻辑的文件名中解析一些数字。我想使用python的方式“尝试,你将被宽恕”,或尝试 - 除了结构。现在我要添加两个以上的案例。这样做的正确方法是什么?我现在想要嵌套尝试或尝试 - 除了传递,尝试 - 除 - 传递,...哪一个会更好还是别的什么?工厂方法也许(如何?)?

将来很容易扩展,因为会有更多的案例。

以下是我想要的(不起作用,因为每次尝试只能存在一个例程):

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',''))

修改

哇,谢谢你的回答,但没有模式匹配。我的坏,在开始时加上“一些共同的逻辑”(现在改为“没有共同的逻辑”,对此抱歉)。在上面的情况下,模式非常相似......让我添加一些完全不同的东西来说明问题。

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

2 个答案:

答案 0 :(得分:10)

您可以提取公共结构并列出可能的参数:

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"

对问题编辑的反应更新

这项技术可以通过使用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

答案 1 :(得分:3)

在您的特定情况下,正则表达式将不再需要执行这些try-except块。这样的事情可能会抓住你的案例:

>>> 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')

关于连续尝试 - 除外块的问题,Niklas B.的答案显然很棒。

修改 你正在做的是模式匹配,为什么不使用模式匹配库?如果正则表达式字符串困扰你,有更简洁的方法来做到这一点:

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]

与自定义函数兼容的另一种更通用的方法:

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)