等效于Python的“与” Ruby的“ With”
-
28-09-2019 - |
题
在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.poen方法。
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
我将为他人添加更多解释;信用应该归功于他们。
确实,在红宝石中,正如其他人所说,清理代码在 ensure
条款;但是,在红宝石中包裹东西无处不在,这就是它在Ruby精神上最有效,最多的方法。翻译时,不要直接翻译单词,您会得到一些非常奇怪的句子。同样,不要指望从Python拥有一对一的对象与Ruby。
从您发布的链接中:
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
.
我相信你正在寻找 确保.