iterwith() doesn't need to: __exit__() is invoked automatically when iteration completes and the loop exits.
Serhiy Storchaka mailto:storchaka@gmail.com February 2, 2013 5:50 AM
When should iterwith() call __exit__()?
_______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas Chris Angelico mailto:rosuav@gmail.com February 2, 2013 5:01 AM
If I understand the OP, the issue is that the 'with' creates a name binding and an indentation level for no purpose; it's like doing this:
f = open(path) for line in f: ...
In that instance, it's possible to inline the function call and use its result directly; it would be nice to be able to do the same with a context manager. However, since 'with' isn't an expression, it's not possible to directly inline the two.
I think the utility function iterwith() is a good - and probably the best - method; it demands nothing special from the language, and works quite happily.
ChrisA _______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas Steven D'Aprano mailto:steve@pearwood.info February 2, 2013 4:46 AM On 02/02/13 22:46, Shane Green wrote:
with open(path) as input: for line in input: do(line)
Using with to create reference to opened file returned by open() so it could temporarily be assigned to input for the sole purpose of iterating its contents never sat very well with me.
It's not the *sole* purpose. If all you want it to iterate over the file, you can do this:
for line in open(path): ...
and no context manager is created. The context manager is also responsible for closing the file immediately you exit the block, without waiting for the caller to manually close it, or the garbage collector to (eventually) close it. So it is not *solely* for iteration.
File context managers can also be used for more than just iteration:
with open(path) as input: text = input.read()
with open(path, 'r+') as output: output.write('ZZ')
and so forth.
* The context manager returned by open() exists only to create the context and return reference "input"; * the context and code block created by the "with" only exists for inner "for" loop's code block to execute in.
I don't understand that objection. As I see it, that's a bit like saying "the len function exists only to get the length of objects". What did you expect the context manager to exist for if not to do the things you say?
What am I missing?
Shane Green mailto:shane@umbrellacode.com February 2, 2013 3:46 AM with open(path) as input: for line in input: do(line)
Using with to create reference to opened file returned by open() so it could temporarily be assigned to input for the sole purpose of iterating its contents never sat very well with me.
* The context manager returned by open() exists only to create the context and return reference "input"; * the context and code block created by the "with" only exists for inner "for" loop's code block to execute in.
Now, given a generator function:
def iterwith(cm): with cm as context: if context is None: context = cm for item in context: yield item
The previous code can be turned into:
for line in iterwith(open(path)): do(line)
So, questions: - Is there anything inherently wrong with the idea, or does it exist? - Is it a generally useful tool, or are the examples limited to files? - Is it possible a more general mechanism could have value, such as:
for line in file with open(path) as file: do(line)
The preceding could be leveraged to different effect:
for line in file with locked(path): write(path + ".out", line)
Or, for line in input with nested(open(path),lock,open(opath)) as input,locked,output: output.write(line)
To revisit the original purpose of "with", this seems to cleanly address a very common scenario wherein:
resource = create_resource() try: for item in resource: do_something(resource, item) except: raise finally: cleanup()
# Standard with approach... with create_resource() as resource: for item in resource: do_something(resource, item)
# With for loop as context... for item in resource with create_resource() as resource: do_something(resource, item)
And, given the translation into statements, maybe even crazy stuff...
[line for line in file with open(path) as file]
J/K, I think.