2

I'm pretty new to Python programming and I have gotten stuck on how to return the data in a function in reverse.

For example, if data.txt contains:

Chaos reigns within. 
Reflect, repent, and reboot 
Order will return.

A call to write_reversed('data.txt') will print:

Order will return.
Reflect, repent, and reboot
Chaos reigns within.

The code I have currently written is

def write_reversed(filename):
    """returns with words in reverse order in the file"""
    with open(filename, 'r') as write_reversed:
        for line in write_reversed:
            return filename[::-1]

I have pasted my code into a Pylint checker and it says "unused variable 'line'"

Kevin
  • 74,910
  • 12
  • 133
  • 166
Saxasianguy
  • 47
  • 1
  • 1
  • 7
  • 2
    You’re returning instead of printing and reversing the filename instead of the lines of the file. There’s a `reversed` function available that you can use on `write_reversed`; it’ll return an iterator (like `write_reversed`) that you can use `for` with. – Ry- Apr 11 '15 at 01:37
  • 1
    It looks like your question has already been answered [here](http://stackoverflow.com/a/2301792/2444609). I would recommend using [this](http://stackoverflow.com/a/23646049/2444609) if it's a big file. – the7erm Apr 11 '15 at 01:52

5 Answers5

1

You are getting the unused variable error because (obviously) you aren't using the variable after declaration. Perhaps you meant:

for line in write_reversed:
     return line[::-1]

However, you can do the following

def write_reversed(filename):
    """returns with words in reverse order in the file"""
    content = []
    with open(filename, 'r') as write_reversed:
        for line in write_reversed:
            content.append(line)
    return list(reversed(content))
A.J. Uppal
  • 19,117
  • 6
  • 45
  • 76
  • `for line in write_reversed: return line[::-1]` will return only the first line, with the characters reversed. The desired output is the whole input file with its lines in reverse order. – TigerhawkT3 Apr 11 '15 at 01:41
  • Besides the confusingness of reusing the function name as a local variable name, why are you doing that whole loop in the first place, when it has the same effect as `content = list(write_reversed)` or `content = write_reversed.readlines()`? Besides that, why make a list out of the iterator in the first place? – abarnert Apr 11 '15 at 01:51
0

First, it says "unused variable line" because you never use line. You should be using it instead of filename - as it is, you're opening a file, then for each line in the file you return the filename backwards (which only happens once, because return will end the function).

Instead, build up a list, then return the reversed list.

def write_reversed(filename):
    """returns with words in reverse order in the file"""
    reversed = []
    with open(filename, 'r') as write_reversed:
        for line in write_reversed:
            reversed.append(line)
    return reversed[::-1]
TigerhawkT3
  • 48,464
  • 6
  • 60
  • 97
  • As with A.J's answer, why are you building up a list in the first place—and, even if you need a list, why do it in such a clunky way instead of just calling `list(write_reversed)`? – abarnert Apr 11 '15 at 01:54
  • How does it add any clarity to build up a list in a clunky way instead of the obvious and simple way? – abarnert Apr 11 '15 at 02:21
  • Going through a loop to append items isn't "clunky." It demonstrates how to iterate through lines in a file while accomplishing a simple task, and, on top of that, it actually did what the question asked for. Why downvote this as unhelpful? – TigerhawkT3 Apr 11 '15 at 02:25
  • "I'm having a bad day and misery loves company" votes are always fun. :P – TigerhawkT3 Apr 11 '15 at 02:30
  • It definitely is clunky to write something unnecessarily complicated that does exactly the same thing as a builtin for no good reason. Why didn't you also write a loop to reverse the list instead of using `reversed` or `[::-1]`? Or use `TextIOBase(BufferedReader(FileIO(…)))` instead of `open`? – abarnert Apr 11 '15 at 02:55
  • And meanwhile, I don't know what you mean by "I'm having a bad day and misery loves company" votes. I'm not downvoting people because I got downvoted (I don't even _have_ an answer to get downvoted) or anything like that; I'm downvoting answers because they don't add anything that isn't already in better answers, except for things that shouldn't be added. – abarnert Apr 11 '15 at 02:56
  • I was trying to "fix" the OP's code into something similar yet functional, so he can see and understand the mistakes he made. Also, when I posted, there were no other "better answers" because there were no other answers. I'm sorry that you woke up on the wrong side of the bed today, but my answer answered the question and solved the problem (without my needing to be reminded of what the question actually was), so I think it's helpful and I'm leaving it here. – TigerhawkT3 Apr 11 '15 at 03:24
  • I don't know why you keep trying to make this personal. I upvoted a number of other questions and answers today, and I downvoted a number of others—not because half of me woke up on the right side of the bed and half of me woke up on the wrong side, and not because I like some people and dislike other people, but because I think some of the questions and answers are useful and others are not. – abarnert Apr 11 '15 at 03:36
  • And there's no reason to take a vote as a comment on you as a person. I have plenty of answers that turned out to be useless, or even misleading, because I didn't read the OP's mind correctly or didn't know about some better option or just wasn't thinking clearly. Sometimes I delete those answers, sometimes I let them collect downvotes because I think they're useful despite the negatives, but I don't get angry about them or worry about who hates me. (If I really have no clue why there are downvotes, I might ask, to learn something and/or improve the answer, but usually nobody responds.) – abarnert Apr 11 '15 at 03:38
0

You can open the file. readlines will return the lines in the file.

for l in F.readlines()[::-1]:
     print l.strip()

will do the job

If you want to return the content, you just have to write this :

return "\n".join([l.strip() for l in F.readlines()[::-1]])
DavidK
  • 2,495
  • 3
  • 23
  • 38
0

You’re reversing the filename instead of the lines of the file. There’s a reversed function available that returns an iterator over whatever you passed it in reverse. File objects are iterables (that’s why you can loop over their lines using for), so you can just pass yours directly to reversed:

def reversed_lines(filename):
    """returns with words in reverse order in the file"""
    with open(filename, 'r') as f:
        return list(reversed(f))

If the function should print the lines instead of returning them, just use your for with reversed(f) instead of f.

Ry-
  • 218,210
  • 55
  • 464
  • 476
  • I _think_ he may want a single string, rather than a list… in which case you want `return ''.join(reversed(f))`. But I may be reading his mind incorrectly. – abarnert Apr 11 '15 at 01:49
0

I have no idea what your question is, but this is a two-liner:

with open(filename, 'r') as f:
    print(*reversed(f.readlines()), sep='')

You can also simply return the reversed lines as an iterator or a list:

with open(filename, 'r') as f:
    return reversed(f.readlines()) # optional: wrap expr. in list()

Then printing your desired output is as simple as:

reversed_lines = write_reversed(filename)
print(*reversed_lines, sep='')

Note: write_reversed is a bad function name for a function that doesn't actually write anything to a buffer.

Shashank
  • 13,713
  • 5
  • 37
  • 63
  • It's supposed to `return` the content. – TigerhawkT3 Apr 11 '15 at 01:43
  • You don't need to strip the lines and them re-join them with `'\n'` (and probably don't want to, because that will lose any trailing newline); just `''.join` the unstripped lines. But otherwise, nice explanation that tries to cover all the things he could possibly mean. :) – abarnert Apr 11 '15 at 01:50
  • 1
    If you switch to Python 3, you can do things like `print(*reversed_lines, sep='\n')`. :) – TigerhawkT3 Apr 11 '15 at 01:51
  • @TigerhawkT3: Actually, the OP is _already_ using 3.x according to his tags. (Which means this answer needs to be edited to 3.x syntax.) But more importantly, you don't need the `sep='\n'` if you don't `strip` the lines in the first place. – abarnert Apr 11 '15 at 01:53
  • I meant, if Shashank switches to 3, like the cool people. :) And I think the reasoning for stripping the lines is to have something more pure to work with going forward, in case we want to do some other operation on them like adding them into the middle of another string. – TigerhawkT3 Apr 11 '15 at 01:56
  • @abarnert Right sorry, I was carrying over the `rstrip` from the for loop print. The print functions have been updated to Python 3. – Shashank Apr 11 '15 at 01:57
  • @TigerhawkT3 Now it's using Py3 print with unpacking :) – Shashank Apr 11 '15 at 02:01
  • @TigerhawkT3: Well, sure, but that "purity" means you're losing the information about whether or not there's a trailing newline, and you either have to always add one (as the previous version of the answer effectively did) or never add one (as the original version did, which I think is worse). Anyway, it's hard to find anything to complain about in the latest version of this answer (which makes me wonder why someone downvoted it, but all I can do about that is upvote it, which I already did, so…). – abarnert Apr 11 '15 at 02:20
  • The question is whether we want to keep the information about whether or not there's a trailing newline. I haven't seen anything to indicate that we'd want it in this case, and most other cases don't want it, so I think tossing it makes sense here until we learn otherwise. – TigerhawkT3 Apr 11 '15 at 02:23