On 5/18/2019 8:13 PM, Yonatan Zunger wrote: ...
For example, this is a good pattern:
with functionReturningFile(...) as input: doSomething(input)
There are many cases where an Optional[file] makes sense as a parameter, as well; for example, an optional debug output stream, or an input source which may either be a file (if provided) or some non-file source (by default). Likewise, there are many cases where a function may naturally return an Optional[file], e.g. "open the file if the user has provided the filename." However, the following is /not/ valid Python:
with functionReturningOptionalFile(...) as input: doSomething(input)
To handle this case, one has a few options. One may only use the 'with' in the known safe cases:
inputFile = functionReturningOptionalFile(...) if inputFile: with inputFile as input: doSomething(input) else: doSomething(None)
Either all possible arguments to doSomething() are going to have to support the same duck-typed API, or doSomething() is going to have to have special logic to handle some types (specifically None in this case). Rather than propagate this "might be None" behavior in to doSomething(), you'd be much better off with this code (as proposed by Steven D'Aprano, but more similar to your example above): if inputFile := functionReturningOptionalFile(...) is None: doSomethingWithNone() else: with inputFile as input: doSomething(input) You're now making the decision about what to do with None as early as possible, instead of passing it off to any function you're calling. Now doSomething() only need concern itself with file-like objects. So I think adding "make 'with' work with anything" would just enable bad APIs, or duck-typing values just to make them look like other types, without actually doing anything (your DevNullFile example further down). Neither of these is desirable. Eric