Currently I have something like the following
def writeThis(fileHandle, name):
fileHandle.write('Hello ' + name)
writeThis(fh, 'Alice')
Something about this doesn't feel right however, it feels like I should try to minimize side effects and have something like the following
def foo(name):
return 'Hello ' + name
fh.write(foo('Alice'))
Is the second option considered better practice? Does it matter?
-
Something needs to write the file. Maybe not the same function that performs the "logic", but probably a function. ... Right?svidgen– svidgen2019年02月15日 00:06:34 +00:00Commented Feb 15, 2019 at 0:06
2 Answers 2
A function which returns a greeting as a string (your 2nd option) is a better practice. That way, the function has a single responsibility. Your code will be easier to maintain. In the future, you may need to change the file format (say you want to switch from XML to JSON). In the future, your customers may want to use the greeting same in more than one place (say, an e-mail or a GUI).
Returning a string has the disadvantage that you need to concatenate all the output into a string first, which can be inefficient if that string gets large. It might be better to write chunks separately, as soon as they are available.
In contrast, directly writing to a file has the disadvantage that the function is now coupled to a particular output medium (file-handle based output).
In practice, neither of these is a terribly huge issue. You should do whatever feels most natural in that particular case. In your hello-world level example, I'd just return the string.
Alternatives:
Let the function take a callback. The caller can then decide what callback to provide. For example:
def writeThis(write, name): write('Hello ') write(name) # a caller that wants a string parts = [] writeThis(parts.append, 'Alice') result = ''.join(parts) # a caller that wants to write to a file writeThis(fh.write, 'Alice')
Yield chunks of output as soon as available:
def writeThis(name): yield 'Hello ' yield name # a caller that wants a string result = ''.join(writeThis('Alice')) # a caller that wants to write to a file for chunk in writeThis('Alice'): fh.write(chunk)
Just use the file API and use a StringIO adapter if you want a string
def writeThis(fh, name): fh.write('Hello ') fh.write(name) # a caller that wants a string from io import StringIO sio = StringIO() writeThis(sio, 'Alice') result = sio.getvalue() # a caller that wants to write to a real file writeThis(fh, 'Alice')