3 ms·
Ad your last Python example - the preferred method of doing resource cleanup in Python is the 'with' mechanism: with open("x.txt") as f: #do stuff
by praptak 14y ago
Ad your last Python example - the preferred method of doing resource cleanup in Python is the 'with' mechanism:
with open("x.txt") as f:
#do stuff with f
That's it. Obviously, compared to 'defer', it hides stuff - the actual magic happens in special methods __enter__ and __exit__ of the object passed to 'with'.
- masklinn 14y ago> Obviously, compared to 'defer', it hides stuff - the actual magic happens in special methods __enter__ and __exit__ of the object passed to 'with'. Then again, `f.Close()` could hide any "magic" you want as well.
- vidarh 14y agoRuby by convention uses blocks for the same situation: def withSomeResource handle = acquireSomeResource yield handle ensure freeSomeResource(handle) if handle end withSomeResource do |h| h.whatever end File.open and other parts of the standard library does that by default. I imagine the Python implementation of "with" is pretty similar, given that it can be implemented pretty much like this in Ruby, and "(begin) .. ensure .." is pretty much equivalent to "try ... finally ..": def with r r.__enter__ yield(r) ensure r.__exit__ end
- praptak 14y agoThe two mechanisms are not very similar. With the blocks mechanism (if I understand correctly) the resource itself implements a method "execute this code and clean up yourself". This only uses the standard mechanisms of the language (i.e. blocks.) The control is with the resource. Python's 'with' inverts the control - the control is with the language runtime and the resource is passive here. In fact 'with' is a special syntax extension, with calls to hard coded method names (__enter__ and __exit__) done by the Python runtime. The resource itself (or the contextmanager representing it) only implements __enter__ and __exit__ and is passive with regards to this mechanism.
- vidarh 14y ago> With the blocks mechanism (if I understand correctly) the resource itself implements a method "execute this code and clean up yourself". Where the method is doesn't matter, e.g. the (incomplete) example I gave of implementing "with" in Ruby that shows a method that can be defined in the global "main" scope or wherever you want. Some classes implement class-methods to instantiate an object and pass it to a black and free the resource as a convenience, such as File.open, but it could go wherever else. The resource itself most certainly does not need to know a thing about it as long as its API lets you do the cleanup you want/need. > The control is with the resource. The control is with whatever calls yield. Whether that be a method on the global "main" object (closest thing Ruby has to a global, freestanding function) or on the class of the resource itself, or an explicit "begin ... ensure ... end" block if you only need it once. > In fact 'with' is a special syntax extension, with calls to hard coded method names (__enter__ and __exit__) done by the Python runtime. Which is why I gave my example of how I thought "with" would look like in Ruby (as it turns out I missed some exception handling in order for it to be equivalent to the Python version in functionality).
- tsuraan 14y agoWhich is why I gave my example of how I thought "with" would look like in Ruby (as it turns out I missed some exception handling in order for it to be equivalent to the Python version in functionality). What you can't do, though, is express ruby's blocks using python's with statement; ruby is strictly more powerful here. One simple example of this is ruby's fork statement, which runs the code in the block in a process of its own: fork { puts "child" } puts "parent" That will print "child" and "parent" once each, and it works because the fork method has control over the block's execution, so it can choose to only evaluate the block in the child's context. In python, the approximate code would be: with fork(): print 'child' print 'parent' However, python doesn't allow the resource to control block execution, so this code can't work (within standard python; there's a bytecode hack that can make it work, but that's outside the spec). Anyhow, I guess we've diverged pretty hard from the article, but I can never pass up the opportunity to vent against python's with statement.
- masklinn 14y ago> given that it can be implemented pretty much like this in Ruby, and "(begin) .. ensure .." is pretty much equivalent to "try ... finally ..": Note that there's a difference in the handling of exceptions: if an exception is triggered from the `with` block, it is intercepted, provided to __exit__ and can be silenced if needed or desired (by returning a truthy value). So a closer approximation would be: def with r r.__enter__ begin yield(r) rescue Exception => e raise unless r.__exit__(e) else r.__exit__(nil) end end