How can I further shorten this Python script which copies the contents of one file to another file?
Question: I'm reading Zed Shaw's "Learn Python The Hard Way". I'm up to exercise 17 (
<http://learnpythonthehardway.org/book/ex17.html> ) and hit the wall on extra
credit #'s 2 & 3\. Zed wants me to shorten the script by eliminating anything
that isn't necessary (he claims he can get it to run with just one line in the
script).

Here is the original script...

    
    
    from sys import argv
    from os.path import exists
    
    script, from_file, to_file = argv
    
    print "Copying from %s to %s" % (from_file, to_file)
    
    # we could do these two on one line too, how?
    input = open(from_file)
    indata = input.read()
    
    print "The input file is %d bytes long" % len(indata)
    
    print "Does the output file exist? %r" % exists(to_file)
    print "Ready, hit RETURN to continue, CTRL-C to abort."
    raw_input()
    
    output = open(to_file, 'w')
    output.write(indata)
    
    print "Alright, all done."
    
    output.close()
    input.close()
    

Here's what I was able to shorten the script to and still get it to run
properly (by properly I mean that the script successfully copies the intended
text to the intended file)...

    
    
    from sys import argv
    from os.path import exists
    
    script, from_file, to_file = argv
    
    input = open (from_file)
    indata = input.read ()
    
    output = open (to_file, 'w')
    output.write (indata)
    

I got rid of the print commands and the two close commands (please excuse if
I'm using "command" incorrectly...I'm painfully new to coding and haven't
gotten the jargon down yet).

Anything else I try to further shorten the script produces errors. For
example, I tried to combine the "input" and "indata" commands into one line
like so...

    
    
    input = open (from_file, 'r')
    

Then I changed any "indata" references in the script to "input"...

    
    
    from sys import argv
    from os.path import exists
    
    script, from_file, to_file = argv
    
    input = open (from_file, 'r')
    
    output = open (to_file, 'w')
    output.write (input)
    

But I get the following TypeError...

    
    
    new-host:python Eddie$ python ex17.py text.txt copied.txt
    Traceback (most recent call last):
      File "ex17.py", line 10, in <module>
        output.write (input)
    TypeError: expected a character buffer object
    

How would you go about shortening the script further...or shortening it down
to just one line, as Zed suggests he can do?


Answer: The current error you get is due to this:

    
    
    input = open (from_file, 'r')
    
    output.write (input)
    

[write()](http://docs.python.org/library/stdtypes.html?highlight=write#file.write)
wants a string as parameter, you are giving it a file object.

Also, since you are trying to eliminate redundant things/shorten your code,
small item, the default mode for
[opening](http://docs.python.org/library/functions.html#open) files is
`'r'`ead, to that doesn't have to be specified when opening files for reading.

Also consider using the `with` construct to open and manage your files. The
advantage is that the files will be closed for you automatically when you are
done, or an exception is encountered, so no explicit `close()` is required.
E.g.,

    
    
    with open('data.txt') as input:
       ## all of your file ops here
    

The [**PEP08 -- Style Guide for
Python**](http://www.python.org/dev/peps/pep-0008/) (a "must read" for Python
programmers) suggests not space between a function and the opening `(`.

I'm not sure a goal of one-line always results in a better or more readable
solution, so that should be kept in mind.

