Probando algunas ideas ...
Parece que lo ideal sería que desee una expresión con efectos secundarios. Si esto estuviera permitido en 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 ...
... entonces estarías clara y claramente expresando tu intención. Pero no lo es. Si los efectos secundarios fueron permitidos en funciones anidadas, usted podría:
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 ...
Ahora, no sólo es que poniendo feo, pero todavía no es válida código Python - la función anidada 'assign_m' no está permitido modificar el variable m
en el alcance externo. Lo mejor que puedo llegar a es realmente feo, usando clase anidada que se deja efectos secundarios:
# 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 ...
Pero eso es claramente un exceso.
Usted migth considerar el uso de una función interna para permitir salidas de ámbito local, lo que le permite eliminar el else
anidación:
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()
Esto le permite acoplar anidación = (2 * N-1) a la anidación = 1 , pero es posible que acabe de mover el problema de los efectos secundarios, y es muy probable que las funciones anidadas confundan a la mayoría de los programadores de Python.
Por último, hay maneras de lado libre de efectos de hacer frente a este:
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)
)),
...)
y ahora el código apenas incluso ve como Python, y mucho menos comprensible para los programadores de Python (es que Lisp?) .
Creo que la moraleja de esta historia es que Python no está optimizado para este tipo de expresiones idiomáticas. Realmente necesita ser un poco detallado y vivir con un gran factor de anidación de otras condiciones.
Ojalá el módulo tuviera un formulario de mantenimiento del estado, también. Pero no considero hackoso crear tu propio objeto que mantenga el estado. Parece una solución limpia, localizada y bien definida para mí. –