i have a big block of code the i do not want to duplicate. in one case i want the block to be done with f as an opened file that gets closed at the end. in the other case it should output to stdout without closing stdout. at first i did it like this:
for name in all_the_names:
with stdout if 'stdout' in options else open(f'{name}.log','w') as f:
...
print(...,file=f) # many lines of code here, do not copy
...
then i realized that the
with might cause stdout to be closed. would that really happen? if so, how can i avoid that?
A contextmanager should do the trick (to be tested)
from contextlib import contextmanager
import sys
@contextmanager
def outfile(name, use_stdout):
if use_stdout:
yield sys.stdout
else:
with open(f'{name}.log', 'w') as f:
yield f
for name in all_the_names:
with outfile(name, stdout in options) as f:
print('Spam', file=f)
could that work for this other thing i want do? i want to be able to open and write a file with a temporary name of my choice and when
with closes it, it also gets renamed to the permanent name.
for name in names:
t = int(time.time()*3906250)
with tmpopen(f'{name}-(t)',name,'w') as f
print('#!/usr/bin/env python3',file=f)
print('# put your code here:',file=f)
Skaperen Wrote:could that work for this other thing i want do?
Of course it would, you only need to rename the file after the 'with open...' block in the contextmanager. But I think we already discussed this problem in the forum and we wrote a solution somewhere.
i want to do it within the with statement so that it is sure to happen (or at least be attempted). sure, i can do it after the with. i can close the file after the with, too. the justification for using with to do a close ... i want to use for doing the rename, too. so i would expect a method that returns an object with a context manager that takes care of both the close and the rename.
It is after the with statement in the context manager but it is included in the with statement for the code that uses the contextmanager.
i thought with called some special method on the file(-like) object used in the with statement that does a close on the file.
Skaperen Wrote:i thought with called some special method on the file(-like) object used in the with statement that does a close on the file.
In the statement
with foo as bar:
spam()
bar
is not
foo
, it is the value returned by
foo.__enter__()
which can be anything, including a file object. At the end of the with statement's execution, no method is called on
bar
, but the method
foo.__exit__()
is called.
It often happens that foo and bar are the same object, for example when foo is the result of a call to
open()
. The
__exit__()
method on a file object calls the
close()
method, but in general you can program whatever behaviour at a block's exit, even if bar is a file object.
The use of a context manager together with sys.stdout does not make much sense, because the fd is open until the program ends.
import os
with os.fdopen(sys.stdout.fileno(), 'w', closefd=False) as fd:
fd.write('Hello World\n')
# is still open
sys.stdout.write('Hello World\n')
It makes sense here because Skaperen wants the same client code whether he uses stdout or a regular file. It's an API normalization.