2012-09-26 8 views
10

私はコンテキストマネージャクラスを定義していますが、インスタンス化中に特定の条件が満たされていれば例外を発生させずにコードブロックをスキップできます。たとえば、-with-blockの実行をスキップする

class My_Context(object): 
    def __init__(self,mode=0): 
     """ 
     if mode = 0, proceed as normal 
     if mode = 1, do not execute block 
     """ 
     self.mode=mode 
    def __enter__(self): 
     if self.mode==1: 
      print 'Exiting...' 
      CODE TO EXIT PREMATURELY 
    def __exit__(self, type, value, traceback): 
     print 'Exiting...' 

with My_Context(mode=1): 
    print 'Executing block of codes...' 
+0

私はこれを見つけましたが、私はそれを理解する方法やそれをどのように実装するのかについてよく分かりません。 http://www.python.org/dev/peps/pep-0377/もっと洗練された方法がありますか? –

+0

それがPEPであるという事実(そして意味論的変更の議論)は、通訳者の振る舞いを変えることに頼らずに実現できないことを示唆しています。 – nneonneo

+2

はきちんとしていますか? :) A()、B():Bの__enter__が何かを上げることができるのは私にとってはうまくいくようです。 – swang

答えて

8

あなたは(特にAnonymousBlocksInPythonから)withhacksからのアイデアを使用してアドホックソリューションをしたい場合、これは動作します:

import sys 
import inspect 

class My_Context(object): 
    def __init__(self,mode=0): 
     """ 
     if mode = 0, proceed as normal 
     if mode = 1, do not execute block 
     """ 
     self.mode=mode 
    def __enter__(self): 
     if self.mode==1: 
      print 'Met block-skipping criterion ...' 
      # Do some magic 
      sys.settrace(lambda *args, **keys: None) 
      frame = inspect.currentframe(1) 
      frame.f_trace = self.trace 
    def trace(self, frame, event, arg): 
     raise 
    def __exit__(self, type, value, traceback): 
     print 'Exiting context ...' 
     return True 

は次の比較:

with My_Context(mode=1): 
    print 'Executing block of code ...' 

with My_Context(mode=0): 
    print 'Executing block of code ... ' 
+0

これは私が探していたものです。 40代。 –

+1

私はそれが__exit __()メソッドによって捕捉され、抑制された何らかの形でTypeErrorをトリガしていることを知っています。面白い仕事! –

+0

メソッド__exit __()にifループを追加して、タイプと値をチェックし、ハックによって発生した例外のみが抑制されるようにしました。 –

1

あなたがしようとしていることは、残念ながら不可能です。 __enter__が例外を発生させた場合、その例外はwithステートメント(__exit__は呼び出されません)で発生します。例外が発生しない場合は、戻り値がブロックに送られ、ブロックが実行されます。これはまた、あなたが通常のbreak文をシミュレートするためwithブロックの途中でBreak()を上げることができます

class Break(Exception): 
    pass 

class MyContext(object): 
    def __init__(self,mode=0): 
     """ 
     if mode = 0, proceed as normal 
     if mode = 1, do not execute block 
     """ 
     self.mode=mode 
    def __enter__(self): 
     if self.mode==1: 
      print 'Exiting...' 
     return self.mode 
    def __exit__(self, type, value, traceback): 
     if type is None: 
      print 'Normal exit...' 
      return # no exception 
     if issubclass(type, Break): 
      return True # suppress exception 
     print 'Exception exit...' 

with MyContext(mode=1) as skip: 
    if skip: raise Break() 
    print 'Executing block of codes...' 

:私は考えることができ

最も近いものは、ブロックによって明示的にチェックフラグです。

with EXPR as VAR: 
    BLOCK 

+0

フラグは機能しますが、私はすべてのチェックをコンテキストマネージャー内に保持し、コードブロックをきれいに保ちたいと思います。それが不可能な場合、私は他の方法を見つける必要があるかもしれません。あまりにも多くのアンありがとう! –

10

PEP-343によると、withの文から翻訳あなたが見ることができるように

mgr = (EXPR) 
exit = type(mgr).__exit__ # Not calling it yet 
value = type(mgr).__enter__(mgr) 
exc = True 
try: 
    try: 
     VAR = value # Only if "as VAR" is present 
     BLOCK 
    except: 
     # The exceptional case is handled here 
     exc = False 
     if not exit(mgr, *sys.exc_info()): 
      raise 
     # The exception is swallowed if exit() returns true 
finally: 
    # The normal and non-local-goto cases are handled here 
    if exc: 
     exit(mgr, None, None, None) 

、あなたが呼び出しからの__enter__()方法に行うことができます明らかには何もありませんwith文の本文( "BLOCK")をスキップできるコンテキストマネージャ。

withhacksなどのプロジェクトでは、__enter__()内の呼び出しスタックを操作するなど、Python実装固有の処理が行われました。私はAlex Martelliが1年か2年前にstackoverflowで非常に面白いハッキングをポストすることを思い出しました。

しかし、あなたの質問/問題に対する簡単な答えは、いわゆる「深い魔法」(これは必ずしもpythonの間では移植可能ではない)を使用せずに、with文の本文をスキップして、実装)。深い魔法で、あなたはそれをすることができるかもしれませんが、私はそれがどのように行われるかも知れないという演習のようなことをするだけで、「生産コード」では決してしないことをお勧めします。

+1

ああ、私の神の 'withhacks'は、狂気です、彼らはPythonでRubyスタイルのブロックを作った... – nneonneo

+0

OK、これはたくさん説明します。私はwithhacksをチェックアウトした。現時点では私の外にあると思う....コードを使ってスキップを実行する方法はまだ分かっていないが、使用できるコードの抜粋は間違いない。 (更新:RUBY STYLE BLOCKS?私はハハ、実際には全く気違いです) そうでなければ、私は本当に別のアプローチを考える必要があります。ありがとうございました! –

関連する問題