Learn Python the Hard Way Exercise 17 Extra Question(S)

Question:

I’m doing Zed Shaw’s fantastic Learn Python The Hard Way, but an extra question has me stumped: Line 9–10 could be written in one line, how? I’ve tried some different thoughts, but to no avail. I could move on, but what would the fun in that be?

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

Zed also writes that he could do the whole script in one line. I’m not exactly sure what he means by that.

Feel free to help me however you want: by giving the answer or merely hinting—and perhaps including a collapsed or hidden answer to the question.

Asked By: Kiwi

||

Answers:

indata = open(from_file).read()
Answered By: GSto

shutil is the way to do one-liner file copies in Python:

shutil.copy(sys.argv[1], sys.argv[2])

Putting the import shutil, sys on the same line as this one (with a semicolon in-between, of course) would however be stylistically goofy;-).

Answered By: Alex Martelli

Well you can just do “algebraic substitution,” right? …assuming you don’t care about the “UI”…

open(to_file, 'w').write(open(from_file).read())
Answered By: dash-tom-bang

I agree with the algebraic substitution mentioned by @dash-tom-bang.
My functioning Exercise 17 extra credit has 5 lines. The operation is being conducted on one line.

open(to_file, ‘w’).write(open(from_file).read())

followed by a simple ‘print’ for verification feedback

print “File %s copied to %s” % (from_file, to_file)

I should have a 6th line that replaces the original ”output.close” but I am confused about how to do this without the ”output” variable? Ahh, since I now have no output variable there is nothing to close.

btw- It is a little spooky for me to see the same exact line typed here that I have worked out and entered myself in gedit. Great stuff, I am really enjoying the mental challenge and community support.

Edit:answered my own question

Answered By: user492743

try the following code:

import shutil, sys; shutil.copy(sys.argv[0], sys.argv[2])
Answered By: karlzt
from sys import argv
open(argv[2], 'w').write(open(argv[1]).read())
Answered By: scc

He answers this below in the section “Common Student Questions”:

No way you can make this one line!

That ; depends ; on ; how ; you ; define ; one ; line ; of ; code.

Answered By: Michael Burns
output = open(to_file, 'w')
output.write(indata) 

can be written as

open(to_file, 'w').write(indata)
Answered By: Huong

Hey Kiwi (and whomever else finds this!),

I’m on the same exercise and I believe I’ve cracked it.

There are two possible readings of Shaw’s “I could make this one line long” tease.

  1. He could make the Python script one line long, upon importing all the necessary commands from the modules, e.g from sys import argv, etc.
  2. He could copy the contents of one file to another in one line using the command line.

I personally think he means the latter, but I will explain both solutions for the sake of learning!

The first (Long) solution:
You must acknowledge that you require the importx from y lines in the Python file, otherwise argv and exist won’t work because they will only have been implicitly referenced, i.e. you haven’t made it clear to Python that you want to use these functions.

The next thing to do is delete all irrelevant code, with irrelevant being code that is written for the benefit of the user, i.e. print, raw_input(), len(), etc.

If you do this, you will be left with:

from sys import argv
from os.path import exists

script, from_file, to_file = argv

indata = open(from_file).read()

out_file = open(to_file, 'w')
out_file.write(indata)

out_file.close()
in_file.close() 

To make this even shorter, you can begin nesting the variables and function in one another. This is the same principle as in maths when you could define a function and then substitute the variable representing that function into another function.

For example:

y = x + 3
z = y, which is essentially z = (x + 3)

If you work this through, you can simplify the code down to:

from sys import argv
from os.path import exists

script, from_file, to_file = argv

(open(to_file, 'w').write(open(from_file).read()))

You can then use lots of ; to link up all the lines of code and vio-la you’re done.

Note: You don’t need to close the files, as you did in the original, as Python will automatically close them upon executing the script.

The second (Short) solution:

If you look at his ‘What You Should See’ section, he uses cat in the terminal. This is short for concatenation, which is a means of connecting strings together. If you combine it with > you can overwrite the contents of one file with another in one line:

cat from_file.txt > to_file.txt

That’s it. One line that will take the contents of one file and put it into another.

Of course, both solutions aren’t perfect, as the first isn’t truly one line and the second doesn’t even use Python!

Feedback appreciated, I only started doing this two days ago…

Answered By: s3nryaku

Cutting away everything you don’t need, all the ‘features you don’t need’ as Zed puts it, and you get one line. It’s even less than 80 characters in length, can’t get much more ‘pythonic’ than that!

from sys import argv; s, f, t = argv; (open(t, ‘w’).write(open(f).read()))

Answered By: niten1

All he is saying is that you can use a semicolon to put two lines onto one line and have it run

in_file = open(from_file);  indata = in_file.read()

You could do that with the whole piece of code if you wanted to

Answered By: TTF

I’m also doing the same book online. I tried this, and it worked:

open(to_file, 'w').write(open(from_file).read())

In other words, I opened the file I was copying to in the write mode and then inserted the contents of the file I was copying from, after opening and reading it, into the write function. I checked my files and it worked. Yay!

Answered By: Laura

Had some fun with this one. In answering this I was looking for a solution that preserved the functionality, used the file commands the exercise was about and did not use “;” to combine lines. Closest I could come is

open(input("Out?: "), 'w').write(open(input("In?: ")).read())

Not quite the same functionality as it prompts for input rather than taking command line. But a single line that gets the job done while using the file commands in the exercise and avoiding concatenating lines using semi colon.

Answered By: Gordon

The below line worked for me:

open(to_file, 'w').write(open(from_file).read())
Answered By: nikgame

There was a hint within the Common Student Questions section:

"No way you can make this one line!
That ; depends ; on ; how ; you ; defi ne ; one ; line ; of ; code."

Note: This is clearly not best practice and difficult to read.

from sys import argv
script, from_file, to_file = argv
in_file = open(from_file); indata = in_file.read(); out_file = open(to_file, 'w'); out_file.write(indata); out_file.close(); in_file.close()
Answered By: secxilio

This the most reduced code that preserves the ui maybe there is other better solutions.

From 21 lines down to 8 lines of code.

Before:

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

To:

from sys import argv
from os.path import exists

script, from_file, to_file = argv

output = open(to_file, 'w').write(open(from_file).read())

print("""Copying from %s to %snThe input file is %d bytes longnDoes the output file exist? %rnReady, hit RETURN to continue, CTRL-C to abort.nAlright, all done.""" % (from_file, to_file, len(open(from_file).read()), exists(to_file)))
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.