1

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 Feb 15 at 0:06
4

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).

4

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')
    

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.