0

Dear community I have a problem that although it's seems to be not a big deal, it took away sleep from me. and I don't need sleep, I NEED answer!

I want to open a file, and if the string "MODIFIED" was in the file's content, I want to print('already modified'), then printing the content of the file here is my code:

with open(f"contents\\docs.txt", "r") as f:
    if "MODIFIED" in f.readlines():
        print("already modified")
    
    print(f.readlines())
    print()

it's seems to be ok, but the weird part is, the file does not contain the string "MODIFIED", so it's just have to normally print the content of the file, but is only return a empty list [] ! (The file is not empty!) and if I run it without the if statement, it will normally return the content as it should.

with open(f"contents\\docs.txt", "r") as f:
    #if "MODIFIED" in f.readlines():
        #print("already modified")
    
    print(f.readlines())
    print()

I just don't get it, what does a if statement do to the code that the code return empty list.

  • the doc.txt file that I want to return it's content
before the flood
david attenborough: a life on our planet
an inconvenient truth
home 2009
kiss the ground 2020
seaspiracy 2020
cosmos

it's the first time I'm encountering this, idk what to call it, bug?
I would appreciate if you guys help me find out what's going wrong

Yasin
  • 13
  • 5
  • 2
    `"MODIFIED" in f.readlines()` will return False everytime since "MODIFIED" is a string compared against a list. Do `"MODIFIED" in f.read()`. – thethiny Sep 06 '22 at 16:48
  • The condition will never be true because `readlines()` keeps the newlines at the end of each line. You need to strip those off first. Then it will match a line that contains only `MODIFIED`. – Barmar Sep 06 '22 at 16:51
  • Where is `MODIFIED` in your sample file? – Barmar Sep 06 '22 at 16:51
  • @Barmar even if that's the case he's using `in` and not `=` – thethiny Sep 06 '22 at 16:59
  • @thethiny What's wrong with that? `string in list_of_strings` is fine. – Barmar Sep 06 '22 at 17:01
  • @Barmar as discussed in the current top-voted answer, we're pending OP's response. – thethiny Sep 06 '22 at 17:09

2 Answers2

2

When you read from a file, it saves where you left off. readlines reads the whole file, so when you call readlines again, there is nothing left to read. Store it in a variable:

with open(f"contents\\docs.txt", "r") as f:
    lines = f.readlines()
    if "MODIFIED" in lines:
        print("already modified")
    print(lines)

Note: this still won't work unless you strip off the trailing '\n's at the end of each line. An alternative is to join lines by a \n so you get a string not a list.

with open(f"contents\\docs.txt", "r") as f:
    lines = f.readlines()
    if "MODIFIED" in '\n'.join(lines):
        print("already modified")
    print(lines)

However, this is not good practice, so this is another alternative:

with open(f"contents\\docs.txt", "r") as f:
    lines = f.read().splitlines()
    if "MODIFIED" in lines:
        print("already modified")
    print(lines)

splitlines does not have the trailing \n.

The Thonnu
  • 3,578
  • 2
  • 8
  • 30
  • 2
    `if "MODIFIED" in lines:` will never be `True` though. – Axe319 Sep 06 '22 at 16:50
  • @Axe319 - added alternative to fix that problem. – The Thonnu Sep 06 '22 at 16:53
  • 1
    @TheThonnu, that's a very silly alternative. Why read line-by-line and then join them into a string instead of just reading the data as a big string (and not using `readlines` at all) in the first place? Doing the work to split them only to join them back together... what's the point? – Charles Duffy Sep 06 '22 at 16:53
  • @CharlesDuffy - I know, but it still works, with minimal change to the OPs original code. – The Thonnu Sep 06 '22 at 16:55
  • Sure, but if we're a teaching resource, we should be showcasing best practices rather than preserving peoples' mistakes, unless we know they made that mistake deliberately / for a purpose. – Charles Duffy Sep 06 '22 at 16:56
  • @CharlesDuffy - added another alternative. – The Thonnu Sep 06 '22 at 16:57
  • This answer does not solve OPs question. `"MODIFIED" in lines` is always false regardless of the trailing `\n` since `in` compares `in` and not `=`. – thethiny Sep 06 '22 at 17:01
  • @thethiny - I don't get what you mean. I've tested it and it works. What do you mean by '*`"MODIFIED" in lines` is always false*'? It's not. – The Thonnu Sep 06 '22 at 17:02
  • @TheThonnu What did you test it against? `if "MODIFIED" in ["line1", "line2", "line3", "MODIFIED"]` would work but OP asked if the string is in the file, not a line on its own. – thethiny Sep 06 '22 at 17:05
  • @thethiny - we don't know that. [Barmar asked OP](https://stackoverflow.com/questions/73625360/if-statement-in-opening-a-file-indention/73625396?noredirect=1#comment130013922_73625360) where "MODIFIED" was in the file, but OP didn't respond. And even if it's not on it's own in a line, my first alternative solution handles that. – The Thonnu Sep 06 '22 at 17:08
  • @TheThonnu Alright then in that case I cannot disagree with you. I have provided an alternative solution on my own that handles both of these cases but still approved your solution. – thethiny Sep 06 '22 at 17:08
  • Thanks guys! all of you helped me, I have read all the comments and learned lot, now I can finally shut my eyes. – Yasin Sep 06 '22 at 17:14
  • and because you asked, "MODIFIED" is on a newline (first or last line).but it doesn't matter now because I have already got my answer, thanks to you guys. – Yasin Sep 06 '22 at 17:19
0

"MODIFIED" in f.readlines() will always evaluate to False since "MODIFIED" is a string while f.readlines() is a list of str. Therefore it will compare "MODIFIED" with every element of that list. As stated by This Answer readlines would also add the trailing \n for each line, so even if your file contains MODIFIED it would actually be read as MODIFIED\n, which makes the evaluation come to False. However as pointed out in the comments by Aran-Fey the evaluation can become True if MODIFIED was the last line in the file and there was no newline at the end.

A trailing \n would not affect your comparison if you were comparing a string against another as in checks for in and not for equality, which is what = does. Therefore "MODIFIED" in "IAMAMODIFIEDSTRING" is True.

The right thing to do would be to replace it with in f.read() which makes the solution as follows:

with open(f"contents\\docs.txt", "r") as f:
    data = f.read()
    if "MODIFIED" in data:
        print("already modified")
    
    print(data)
    print()

However, if you want to make sure MODIFIED is on a line on its own then you would do:

with open(f"contents\\docs.txt", "r") as f:
    data = f.readlines()
    if "MODIFIED" in [line.strip() for line in data]:
        print("already modified")
    
    print('\n'.join(data))
    print()
thethiny
  • 1,125
  • 1
  • 10
  • 26
  • 2
    `"MODIFIED" in lines` can actually return True if it's the last line and the file doesn't end with a newline. – Aran-Fey Sep 06 '22 at 17:10
  • I don't understand what you're saying. `string in list` works if the elements of the list are strings. E.g. `"abc" in ["foo", "abc", "bar"]` – Barmar Sep 06 '22 at 17:10
  • Thanks guys! all of you helped me, I have read all the comments and learned lot, now I can finally shut my eyes. – Yasin Sep 06 '22 at 17:12
  • @Aran-Fey I actually missed that. Thanks for notifying me. – thethiny Sep 06 '22 at 17:15
  • @Barmar I was editing the question when you posted your comment by adding an explanation. – thethiny Sep 06 '22 at 17:15