2016-08-24 2 views
0

カスタマイズしたループ動作を実装しています。ループに入るとき、すべてのループ開始時、すべてのループ終了時、およびループ領域を終了するときに起こることが必要です。これまでのところ、これは、Python(2.7)で美しくシンプルです:カスタムイテレータまたはジェネレータがブレーク後にクローズアウトを実行する

def my_for(loop_iterable): 
    enter_loop() 
    for i in loop_iterable: 
     loop_start() 
     yield i 
     loop_end() 
    exit_loop() 

for i in my_for([1, 2, 3]): 
    print "i: ", i 
    if i == 2: 
     break 

私がいる問題はbreak後に実行するloop_end()exit_loop()を得ることにあります。その行を追加するために覚えておく必要が

def break_loop(): 
    loop_end() 
    exit_loop() 

for i in my_for([1, 2, 3]): 
    print "i: ", i 
    if i == 2: 
     break_loop() 
     break 

しかし、私は本当にのようなユーザを持っていないでしょう。私は、ユーザーがブレークする前に置く必要があり、別の関数を定義することによって、これを解決してきました。私は、イテレータクラスとしてジェネレータ関数を書き直すと、おそらくbreakでコードを実行する方法があると思いますか?

ちなみに、continueはそのまま動作します。

+0

なぜカスタマイズされたループ動作を実装していますか? – Blender

答えて

0

あなたが使用することができcontext manager

class Looper(object): 
    def __init__(self, iterable): 
     self.iterable = iterable 
     self.need_to_end = False 

    def __enter__(self): 
     return self 

    def __exit__(self, exception_type, exception_value, traceback): 
     self.exit_loop() 
     # Handle exceptions or swallow them by returning True 

    def enter_loop(self): 
     print 'enter_loop' 

    def loop_start(self): 
     self.need_to_end = True 
     print 'loop_start' 

    def loop_end(self): 
     self.need_to_end = False 
     print 'loop_end' 

    def exit_loop(self): 
     if self.need_to_end: 
      self.loop_end() 

     print 'exit_loop' 

    def __iter__(self): 
     self.enter_loop() 

     for i in self.iterable: 
      self.loop_start() 
      yield i 
      self.loop_end() 

あなたのコードが少し長くなるだろうが、あなたはもっときれいに例外や他のものを扱うことができます。

with Looper([1, 2, 3, 4, 5, 6]) as loop: 
    for i in loop: 
     print i 

     if i == 2: 
      continue 
     elif i == 3: 
      break 

それはあなたがしたいように動作期待するもの:

enter_loop 
loop_start 
1 
loop_end 
loop_start 
2 
loop_end 
loop_start 
3 
loop_end 
exit_loop 
+0

ありがとうございます! 'self.exited'属性を追加することで、iteratorの最後で(私が持っていたジェネレータとして)' exit_loop() 'を呼び出し、条件付きで' __exit __() 'で' exit_loop() 'はコンテキスト管理を可能にします。魅力的な作品!私はそれを行うための両方の方法を提供します。 –

0

__enter____exit__のマジック関数をクラスで定義することで使用できます。電話をするにはwithと一緒に使うことができます。 withブロック内でコードを実行する前に__enter__メソッドが呼び出され、withブロックが終了すると、__exit__関数が呼び出されます。たとえば:イテレータとしてそれを作るために今すぐ

>>> class MyTestWrapper(object): 
...  def __enter__(self): 
...   print 'I am in __enter__' 
...  def __exit__(self, type, value, traceback): 
...   print 'I am in __exit__' 
... 
>>> with MyTestWrapper() as s: 
...  print 'My Loop Logic' 
... 
I am in __enter__ 
My Loop Logic 
I am in __exit__ 

、あなたは__iter__関数を定義する必要があります。これをイテレータとして呼び出すことができます。更新されたコードは次のようになります。

>>> class MyIterator(object): 
...  def __init__(self, iterable): 
...   self.iterable = iterable 
...   self.need_to_end = False 
...  def __enter__(self): 
...   print 'I am in __enter__' 
...   return self 
...  def __exit__(self, type, value, traceback): 
...   self.loop_end() 
...   print 'I am in __exit__' 
...  def loop_start(self): 
...   self.need_to_end = True 
...   print 'Starting Loop . . . ' 
...  def loop_end(self): 
...   self.need_to_end = False 
...   print 'Ending Loop . . . ' 
...  def __iter__(self): 
...   for i in self.iterable: 
...    self.loop_start() 
...    yield i 
...    self.loop_end() 
... 
>>> with MyIterator([1,2,3, 4]) as my_iterator: 
...  for i in my_iterator: 
...   print 'I am: ', i 
...   if i == 2: 
...    break 
... 
I am in __enter__ 
Starting Loop . . . 
I am: 1 
Ending Loop . . . 
Starting Loop . . . 
I am: 2 
Ending Loop . . . 
I am in __exit__ 

は、これらおよび他の作り付けの機能の詳細については、Python's Context Managerを参照してください。

関連する問題