2012-05-26 19 views
5

Zastanawiam się, czy coś takiego jest możliwe w python (3.2, jeśli jest to istotne).Korzystanie z Context Manager do sterowania przepływem

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

Jeżeli zachowanie jest:

  • jeśli regex meczów, grupy regex przydzielane a i b
    • Jeśli istnieje jakaś niezgodność, że to wyjątek
  • jeśli mecz jest None, to po prostu ominąć kontekst całkowicie

Moim celem jest w gruncie rzeczy niezwykle zwięzły sposób na zachowanie kontekstualne.

Próbowałem czyniąc następujące menedżera kontekstowego:

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) 

to rzeczywiście działa dokładnie tak, jak to pożądane dla przypadku, gdy mecz Wyrażenia regularne, ale, jak widać, to rzuca ValueError jeśli nie ma odpowiednika. Czy jest jakiś sposób, aby zmusić go do "skoku" do sekwencji wyjścia?

Dzięki!

Odpowiedz

4

Ah! Być może wyjaśnienie tego na SO wyjaśniło problem dla mnie. Po prostu używam instrukcji if zamiast instrukcji with z.

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) 

Podaje dokładnie to, co chcę. Pozostawiając to tutaj na wypadek, gdyby inni ludzie chcieli z niego skorzystać. (Modyfikacje, jeśli nie są istotne, możesz je usunąć itp.)

EDIT: W rzeczywistości to rozwiązanie ma jedną dość dużą wadę. Robię to zachowanie w pętli for. Więc to mi przeszkadza:

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 

Ponieważ kontynuacja teraz wyłamuje się z tej pętli zamiast rodzica dla pętli. Jeśli ktoś ma sugestie, chciałbym usłyszeć!

EDIT2: W porządku, wymyśliłem to na razie tym razem.

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) 

Przepraszamy za wpis - przysięgam, że naprawdę utknąłem zanim napisałem. :-) Mam nadzieję, że ktoś inny uzna to za interesujące!

+0

można napisać 'dla a, b w ...' – jfs

+2

Jawne "podniesienie StopIteration" jest niepotrzebne. 'if match: yield match.groups()' jest wystarczające. – jfs

+1

Dzięki za napiwek, J.F.! Końcowy kod odzwierciedla twój punkt. –

Powiązane problemy