4
\$\begingroup\$

I just finished working through Exercise 16 of Learn Python The Hard Way. To further study, I wanted to create a script that will read and display a file's contents on screen, and then have the user re-write the file with three lines.

Can my code be written in a much cleaner, pythonic way?

from sys import argv

script, filename = argv

print "The name of the script is: %r" % script

# open txt file and display on screen
text1 = open(filename, 'r')
print text1.read()
text1.close()

# ask user to overwrite the file
print "To overwrite this file, hit <enter>."
print "Otherwise, CTRL-C to escape."
raw_input('> ')

# open the txt file again; overwrite it with different data
# have user input new data for each line
text2 = open(filename, 'w')
print "Write three lines to the file."
line1 = raw_input('line 1: ')
line2 = raw_input('line 2: ')
line3 = raw_input('line 3: ')

text2.write('\n'.join([line1, line2, line3, '']))
text2.close()

# read and display reconstructed file
text3 = open(filename, 'r')
print text3.read()
text3.close()
\$\endgroup\$
3
\$\begingroup\$

First of all I would recommend you to move the code to function so that you can re-use it by importing it in some other module as well.

To differentiate between whether the module has been ran directly or it was imported use the if __name__ = "__main__" condition at the bottom of the code.

Now coming to your code:

  • You don't really need to open the file 3 times to do this. With r+ mode this can be done in a single go. Note that good thing about r+ mode is that it also allows us read as well as write to the file.

  • Use a with statement to handle a file object, it makes sure that the file object gets closed even when an error occurs.

  • Instead of asking the user to hit Enter or CTRL-c ask them for a simply 'yes' or 'no' or may be 'y' or 'n'.

  • You're always writing three lines to the file, you can also ask the user for the number of lines they would like to write. Make this a default variable to the function with value 3 if you want them to write 3 lines by default. You can pass this value using another argument to the script: python foo.py file.txt 10. Using this variable you can run a loop and ask the user to enter the lines they would like to write.

  • Don't create unnecessary variables like line1, line2 and line3, better use a list and append the lines to it within in a loop.

  • Lastly, this is not an issue. But I would recommend that you should use the new-style string formatting over the old printf style string formatting as it is much more powerful and expressive in my opinion.

Code:

from sys import argv


def file_overwrite(filename, n=3):

    with open(filename, 'r+') as f:
        content = f.read()
        print content
        # ask user to overwrite the file
        while True:
            feedback = raw_input("Type 'y' to overwrite the file or 'n' to exit: ")
            if feedback.lower() == 'y':
                # move the file pointer back to the start and then truncate the file
                f.seek(0)
                f.truncate()
                break
            elif feedback.lower() == 'n':
                # return instantly, another advantage of using a function
                return
            else:
                print "Please enter either 'y' or 'n'."

        print 'Write {} lines to the file.'.format(n) 
        # Loop n times and ask for user input and save it in the list.
        lines = []
        for line_num in xrange(1, n+1):
            line = raw_input('line {}: '.format(line_num))
            lines.append(line)

        f.write('\n'.join(lines))

        # After writing the file pointer is again at the end of the file.
        # To read the content again move it back to the start and then
        # read file's content.
        f.seek(0)
        print f.read()

if __name__ == '__main__':

    # The condition will run only when the user runs this file 
    # directly. 

    script, filename = argv[:2]
    print "The name of the script is: {!r}.".format(script)
    try:
        n = int(argv[2])
        file_overwrite(filename, n)
    except (IndexError, ValueError):
        file_overwrite(filename)
\$\endgroup\$
1
\$\begingroup\$

For starters, you should only use 1 variable for opening the files. Instead of having text1, text2, and text3, you could have 1 variable called f. Second, you should use:

with open([file],[I.O. mode]) as f:
    # COMMANDS ...

An example is:

with open("test.txt","w") as f:
    f.write("Hello\n")

Did I mention that the with statement also automatically closes the file once the indent ends?

\$\endgroup\$

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.