2012-05-26 18 views
5

Me pregunto si algo como esto es posible en python (3.2, si es relevante).Usando Context Manager para Control Flow

with assign_match('(abc)(def)', 'abcdef') as (a, b): 
    print(a, b) 

Cuando el comportamiento es:

  • si las coincidencias de expresiones regulares, los grupos de expresiones regulares se asignan a a y b
    • si hay una falta de coincidencia no, sería una excepción
  • si el partido es None, simplemente omitir completamente el contexto

Mi objetivo aquí es básicamente una forma extremadamente concisa de realizar el comportamiento contextual.

he intentado hacer lo siguiente gestor de contexto:

import re 

class assign_match(object): 
    def __init__(self, regex, string): 
     self.regex = regex 
     self.string = string 
    def __enter__(self): 
     result = re.match(self.regex, self.string) 
     if result is None: 
      raise ValueError 
     else: 
      return result.groups() 
    def __exit__(self, type, value, traceback): 
     print(self, type, value, traceback) #testing purposes. not doing anything here. 

with assign_match('(abc)(def)', 'abcdef') as (a, b): 
    print(a, b) #prints abc def 
with assign_match('(abc)g', 'abcdef') as (a, b): #raises ValueError 
    print(a, b) 

En realidad funciona exactamente como se desea para el caso en que el partido de expresiones regulares, pero, como se puede ver, se lanza la ValueError si no hay coincidencia. ¿Hay alguna manera de que pueda "saltar" a la secuencia de salida?

Gracias!

Respuesta

4

¡Ah! Tal vez explicarlo en SO me esclareció el problema. Solo uso una declaración if en lugar de una declaración with.

def assign_match(regex, string): 
    match = re.match(regex, string) 
    if match is None: 
     raise StopIteration 
    else: 
     yield match.groups() 

for a in assign_match('(abc)(def)', 'abcdef'): 
    print(a) 

Da exactamente el comportamiento que me gustaría. Dejando esto aquí en caso de que otras personas quieran beneficiarse de él. (Mods, si no es relevante, siéntase libre de eliminar, etc.)

EDIT: En realidad, esta solución viene con un error bastante grande. Estoy haciendo este comportamiento dentro de un for-loop. Así que esto me impide hacer:

for string in lots_of_strings: 
    for a in assign_match('(abc)(def)', string): 
     do_my_work() 
     continue # breaks out of this for loop instead of the parent 
    other_work() # behavior i want to skip if the match is successful 

Debido a que la siguen ahora escapa de este bucle en lugar de los padres para el lazo. Si alguien tiene sugerencias, ¡me encantaría escuchar!

EDIT2: De acuerdo, esta vez lo descubrí de verdad.

from contextlib import contextmanager 
import re 

@contextmanager 
def assign_match(regex, string): 
    match = re.match(regex, string) 
    if match: 
     yield match.groups() 

for i in range(3): 
    with assign_match('(abc)(def)', 'abcdef') as a: 
# for a in assign_match('(abc)(def)', 'abcdef'): 
     print(a) 
     continue 
    print(i) 

Perdón por la publicación - Juro que me sentía realmente atrapada antes de publicar. :-) ¡Ojalá alguien más lo encuentre interesante!

+0

puede escribir 'for a, b in ...' – jfs

+2

Explicit 'raise StopIteration' no es necesario. 'if match: yield match.groups()' es suficiente. – jfs

+1

Gracias por el consejo, J.F.! El código final refleja tu punto. –