Испытываете некоторые идеи ...
Похоже, вы бы идеально хотели выражение с побочными эффектами. Если это было разрешено в Python:
if m = re.match('foo (\w+) bar (\d+)', line):
# do stuff with m.group(1) and m.group(2)
elif m = re.match('baz whoo_(\d+)', line):
# do stuff with m.group(1)
elif ...
... тогда бы вы четко и чисто выразили свое намерение. Но это не так. Если бы побочные эффекты были разрешены во вложенных функциях, вы могли бы:
m = None
def assign_m(x):
m = x
return x
if assign_m(re.match('foo (\w+) bar (\d+)', line)):
# do stuff with m.group(1) and m.group(2)
elif assign_m(re.match('baz whoo_(\d+)', line)):
# do stuff with m.group(1)
elif ...
Теперь, это не только уродливо, но и все еще недопустимый код Python - вложенная функция assign_m не может изменять переменную m
во внешней области видимости. Лучшее, что я могу придумать, это действительно безобразно, используя вложенный класс, который допускает побочные эффекты:
# per Brian's suggestion, a wrapper that is stateful
class m_(object):
def match(self, *args):
self.inner_ = re.match(*args)
return self.inner_
def group(self, *args):
return self.inner_.group(*args)
m = m_()
# now 'm' is a stateful regex
if m.match('foo (\w+) bar (\d+)', line):
# do stuff with m.group(1) and m.group(2)
elif m.match('baz whoo_(\d+)', line):
# do stuff with m.group(1)
elif ...
Но это явно излишество.
Вы можете рассмотреть возможность использования внутренней функции для разрешения локальных выходов из области, которая позволяет вам удалить вложенность else
:
def find_the_right_match():
# now 'm' is a stateful regex
m = re.match('foo (\w+) bar (\d+)', line)
if m:
# do stuff with m.group(1) and m.group(2)
return # <== exit nested function only
m = re.match('baz whoo_(\d+)', line)
if m:
# do stuff with m.group(1)
return
find_the_right_match()
Это позволяет вам сделать nesting = (2 * N-1) равным nesting = 1, но вы, возможно, только что переместили проблему побочных эффектов, и вложенные функции с большой вероятностью могут запутать большинство программистов Python.
И, наконец, есть способы избавления от побочных эффектов:
def cond_with(*phrases):
"""for each 2-tuple, invokes first item. the first pair where
the first item returns logical true, result is passed to second
function in pair. Like an if-elif-elif.. chain"""
for (cond_lambda, then_lambda) in phrases:
c = cond_lambda()
if c:
return then_lambda(c)
return None
cond_with(
((lambda: re.match('foo (\w+) bar (\d+)', line)),
(lambda m:
... # do stuff with m.group(1) and m.group(2)
)),
((lambda: re.match('baz whoo_(\d+)', line)),
(lambda m:
... # do stuff with m.group(1)
)),
...)
А теперь код, едва даже выглядит как Python, не говоря уже о том, что он понятен программистам Python (это Лисп?).
Я думаю, что мораль этой истории в том, что Python не оптимизирован для такого рода идиом. Вам действительно нужно быть немного многословным и жить с большим фактором вложения других условий.