質問

Pythonで、 with ステートメントは、例外がスローされたり、関数呼び出しが返されたりするにもかかわらず、クリーンアップコードが常に呼び出されるようにするために使用されます。例えば:

with open("temp.txt", "w") as f:
    f.write("hi")
    raise ValueError("spitespite")

ここでは、例外が提起されていても、ファイルは閉じられています。より良い説明です ここ.

Rubyのこの構造に相当するものはありますか?または、Rubyには継続があるので、コーディングできますか?

役に立ちましたか?

解決

Rubyは、文字通りの匿名手順に対して構文的に軽量なサポートを持っています(呼ばれます ブロック ルビーで)。したがって、これには新しい言語機能は必要ありません。

(一般的に、言語機能を追加する必要がある場合、それは悪い兆候です。ライブラリにすべてを実装できるはずです。そうでなければ、それは悪い言語デザインの兆候です。)

したがって、通常、コードのブロックを取得し、リソースを割り当て、そのリソースのコンテキストでコードのブロックを実行してリソースを閉じるメソッドを作成することです。

このようなもの:

def with(klass, *args)
  yield r = klass.open(*args)
ensure
  r.close
end

このように使用できます。

with File, 'temp.txt', 'w' do |f|
  f.write 'hi'
  raise 'spitespite'
end

ただし、これは非常に手続き的な方法です。 Rubyはオブジェクト指向の言語です。つまり、コードブロックを適切に実行する責任は、 File に属する必要があります File クラス:

File.open 'temp.txt', 'w' do |f|
  f.write 'hi'
  raise 'spitespite'
end

これは次のようなものを実装できます。

def File.open(*args)
  f = new(*args)
  return f unless block_given?
  yield f
ensure
  f.close if block_given?
end

これは、Ruby Coreライブラリ、標準ライブラリ、サードパーティライブラリの多くのクラスによって実装される一般的なパターンです。


ジェネリックPythonコンテキストマネージャープロトコルへのより緊密な対応は、次のとおりです。

def with(ctx)
  yield ctx.setup
ensure
  ctx.teardown
end

class File
  def setup; self end
  alias_method :teardown, :close
end

with File.open('temp.txt', 'w') do |f|
  f.write 'hi'
  raise 'spitespite'
end

これはPythonの例とほぼ区別できないことに注意してくださいが、言語に新しい構文を追加する必要はありませんでした。

他のヒント

Rubyの同等物は、ブロックをfile.openメソッドに渡すことです。

File.open(...) do |file|
  #do stuff with file
end  #file is closed

これは、Rubyが使用するイディオムであり、快適になるはずです。

Rubyでこれを行うには、ブロック引数を使用できます。

class Object  
    def with(obj)  
        obj.__enter__  
        yield  
        obj.__exit__  
    end  
end

これで、追加できます __enter____exit__ 別のクラスへの方法とこのように使用します:

with GetSomeObject("somefile.text") do |foo|  
    do_something_with(foo)
end  

他の人にもっと説明を追加するだけです。クレジットは彼らに行くべきです。

確かに、Rubyでは、他の人が言ったとおり、クリーンアップコードは ensure 句;しかし、ブロックで物を包むことはルビーで遍在しており、これがルビーの精神で最も効率的かつ最も行われる方法です。翻訳するときは、単語用語を直接翻訳しないでください。非常に奇妙な文章が得られます。同様に、PythonからすべてがRubyに1対1の対応することを期待しないでください。

投稿したリンクから:

class controlled_execution:
    def __enter__(self):
        set things up
        return thing
    def __exit__(self, type, value, traceback):
        tear things down

with controlled_execution() as thing:
     some code

Ruby Way、このようなもの(男、私はおそらくこれをすべて間違っている:D):

def controlled_executor
  begin
    do_setup
    yield
  ensure
    do_cleanup
  end
end

controlled_executor do ...
  some_code
end

明らかに、両方に引数を追加できます controlled executor (通常の方法で呼び出される)、そして(その場合、ブロックに引数も追加する必要があります)。したがって、上記で引用したものを実装するには、

class File
  def my_open(file, mode="r")
    handle = open(file, mode)
    begin
      yield handle
    ensure
      handle.close
    end
  end
end

File.my_open("temp.txt", "w") do |f|
  f.write("hi")
  raise Exception.new("spitesprite")
end

Rubyで原子的にファイルに書き込むことができます。

File.write("temp.txt", "hi")
raise ValueError("spitespite")

このようなコードを書くことは、ファイルを誤って開いたままにすることが不可能であることを意味します。

いつでも使用できます try..catch..finally ブロック、ここで finally セクションには、クリーンアップするコードが含まれています。

編集:申し訳ありませんが、ミスポーク:あなたは欲しいです begin..rescue..ensure.

私はあなたが探していると信じています 確認.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top