An ex-colleague and good friend asked me to look at some code for her recently - she's trying to learn to code and that's a good thing. I helped her fix a few things but it got me thinking about how many learning points there can be from one snippet.

songs = open("Songs list.txt","r")
songs_list = songs.read().splitlines()
songs.close()

So where do we start? Firstly, that file name. I won't comment on the choice (I don't like spaces or capitalisation,  but that's just me!) More importantly, this should be defined as a constant. A constant is a named memory location which can't (or in the case of Python shouldn't) be changed at runtime. We indicate this in Python by using all capitals for the identifier:

SONGSFILE = "Songs list.txt"
songs = open(SONGSFILE,"r")
songs_list = songs.read().splitlines()
songs.close()

Now what? Well, what if that file doesn't exist? When a file can't be found, Python will raise an error called an exception. What we should do as a minimum is try to catch that and die gracefully. In this case we raise our own exception (SystemExit) which is an elegant way to close the program.

SONGSFILE = "Songs list.txt"
try:
    songs = open(SONGSFILE,"r")
except:
    print("Sorry, I couldn't find the file!")
	raise SystemExit
songs_list = songs.read().splitlines()
songs.close()

But wait - maybe we moved the file? Or changed the name? We can be a little bit clever and give the user the chance to fix the error! Note I'm now using songsfile as a variable (and initialising it with a value) so have changed case.

songsfile = "Songs list.txt"
while True:
    try:
        songs = open(songsfile,"r")
        break
    except:
        print("Sorry, I couldn't find the file!")
        songsfile = input('Enter a correct file name, or hit enter to quit')
        if (songsfile == ''):
            raise SystemExit
songs_list = songs.read().splitlines()
songs.close()

Now we are going to continue trying until we decide to stop. If we get past the open command, then we must have successfully opened the file so we can break out of the loop. If not, then instead of exiting straight away, we ask the user to enter the file name. If they choose to hit enter (i.e. enter an empty string), we exit as before. However, if they do enter something then we go around the loop and try again.

There is of course potential to look at the data and start deciding whether this data file was valid/correct, but that's a different issue. And it was lovely seeing my friend remembered the close command. Normally you won't notice this is missing, until you go to move/delete/edit the data file and find it's locked!

Update

A colleague quite rightly contacted me recently pointing out a lack of pythonic 'correctness' on this page; I have included this below, but thought I'd take the opportunity to explain my reasons.

  1. I learnt to program a long time ago and fell into Python for dubious reasons; therefore I don't always know about Pythonic methods.
  2. I've taught programming in many languages - (most/many?) other languages don't support this syntax.
  3. It feels icky to me - trusting the computer to close a file feels risky to me.

That being said, it's always good to explore different methodologies and I'm more than happy to use and abuse Python as it suits me. So here's Alistair's method.

SONGSFILE = "Songs list.txt"
try:
    with open(SONGSFILE,"r") as songs:
  songs_list = songs.read().splitlines()
except:
    print("Sorry, I couldn't find the file!")
raise SystemExit