Domanda

Sto cercando di scrivere il codice che supporta la seguente semantica:

with scope('action_name') as s:
  do_something()
  ...
do_some_other_stuff()

Il campo di applicazione, tra le altre cose (di impostazione, la pulizia) deve decidere se questa sezione deve essere eseguito.
Per esempio, se l'utente ha configurato il programma per bypass 'action_name' che, dopo l'Ambito di applicazione () viene valutata do_some_other_stuff () verrà eseguita senza chiamare fai_qualcosa () prima.
Ho cercato di farlo utilizzando questo manager contesto:

@contextmanager
def scope(action):
  if action != 'bypass':
    yield

ma un'eccezione RuntimeError: generator didn't yield ottenuto (quando action è 'bypass').
Sto cercando un modo per sostenere questo senza ricadere l'attuazione più prolisso opzionale:

with scope('action_name') as s:
  if s.should_run():
    do_something()
    ...
do_some_other_stuff()

Qualcuno sa come posso raggiungere questo obiettivo?
Grazie!

P.S. Sto usando python2.7

EDIT:
La soluzione non deve necessariamente fare affidamento sulle dichiarazioni with. Io proprio non sapevo esattamente come esprimerlo senza di essa. In sostanza, voglio qualcosa in forma di un contesto (supporta la configurazione e la disinfezione automatica, estraneo alla logica contenuta) e permette l'esecuzione condizionale basata su parametri passati al metodo di impostazione e selezionati nella configurazione.
Ho anche pensato di una possibile soluzione che utilizza decoratori. Esempio:

@scope('action_name') # if 'action_name' in allowed actions, do:
                      #   setup()
                      #   do_action_name()
                      #   cleanup()
                      # otherwise return
def do_action_name()
  do_something()

, ma io non voglio far rispettare troppo la struttura interna (vale a dire, come il codice è diviso per funzioni) sulla base di questi ambiti.
Qualcuno ha alcune idee creative?

È stato utile?

Soluzione

Si sta cercando di modificare il comportamento atteso di un costrutto del linguaggio di base. Che non è mai una buona idea, sarà solo portare a confusione.

Non c'è niente di sbagliato con il work-around, ma si può semplificare un po '.

@contextmanager 
def scope(action): 
  yield action != 'bypass'

with scope('action_name') as s: 
  if s: 
    do_something() 
    ... 
do_some_other_stuff() 

Il tuo scope potrebbe invece essere una classe il cui rendimento sia un oggetto utile o __enter__ e sarebbe essere utilizzato nello stesso modo metodo di None.

Altri suggerimenti

Di seguito sembra funzionare:

from contextlib import contextmanager

@contextmanager
def skippable():
    try:
        yield
    except RuntimeError as e:
        if e.message != "generator didn't yield":
            raise

@contextmanager
def context_if_condition():
    if False:
        yield True

with skippable(), context_if_condition() as ctx:
    print "won't run"

Considerazioni:

  • ha bisogno di qualcuno a venire con i nomi migliori
  • context_if_condition non può essere utilizzato senza skippable, ma non c'è modo di far rispettare che / rimuovere la ridondanza
  • potrebbe prendere e sopprimere il RuntimeError da una funzione più profondo di intesa (un'eccezione personalizzata potrebbe aiutare lì, ma che rende l'intero costrutto Messier ancora)
  • non è più chiaro che solo utilizzando la versione di @ Mark Ransom

Non credo che questo può essere fatto. Ho provato attuazione di un gestore contesto come classe e non c'è modo per forza il blocco per sollevare un'eccezione che in seguito sarà silenziato dal metodo __exit__().

Ho lo stesso caso d'uso come lei, e mi sono imbattuto il condizionale libreria che qualcuno ha utilmente sviluppata nel tempo da quando avete inviato la tua domanda.

Dal sito, il suo utilizzo è come:

with conditional(CONDITION, CONTEXTMANAGER()):
    BODY()
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top