For loop seems to only run once - python

I have built, as part of a project, a very simple program that checks whether or not a given string is present in a provided text file.
The program checks if the input is equal to each line of the file, using a for loop, and returns True if the values correspond, False if the don't.
with open (names, "r") as file:
while True:
name_check = input("name: ")
if name_check == "":
#command to end the program
break
for newline in file:
#compares the input with every line in the txt file
newline_stripped = newline.lower().strip()
if newline_stripped == name_check:
print (True)
else:
print (False)
file.close()
The issue is, when i run the code, the first iteration works fine, it returns a sequence of False and True as intended, and then asks for another input, however when said input is given again, it immediately asks for another one, without returning any sequence, as if the for loop is being skipped entirely.
I tried running it by using a list of numbers instead of a text file as a source (with proper modification) and it runs 100% as intended, so I suspect it has something to do the way it handles the file itself, but I can't figure out why.
Thanks in advance for any help!

You walk through the entire file on the first iteration, so the second iteration has nothing left to read. You can either open the file on each iteration, or move the position to the start by file.seek(0).

Related

Why does my function stops reading from a file after ran through once?

My program is set up to read from a .csv file, basically a .txt file. It asks the user for a str to search for, and then searches through this file and prints out the entire line that its on. The user should be able to run the search method multiple times in a row, but it doesnt work after the first time. If it helps, a print statement when put in the search method does show that it indeed runs the second time, just nothing happens. Any ideas why this happens? Thanks.
def main():
print("\nHello, welcome to Sales Data Menu.")
select=0
inFile = open("sales_data.csv", "r")
while select != 4:
select = int(input("\n1.)Search for an inovice item based on last name or id number.\n2.)Find and display the total number of items on the invoice.\n3.)Find and display the total cost of the invoice.\n4.)Exit the menu.\nEnter a number to select an option to do: "))
if select==1:
search(inFile)
else:
print("You did not enter a valid integer. Please re-enter")
inFile.close()
def search(inFile):
item = input("Enter a last name or an id number to search by.")
for lines in inFile:
if item in lines:
print(lines)
https://www.tutorialspoint.com/python/file_close.htm
Python file method close() closes the opened file. A closed file cannot be read or written any more. Any operation, which requires that the file be opened will raise a ValueError after the file has been closed. Calling close() more than once is allowed.
the problem is probably on that line:
inFile.close()
When you use the file object itself in a loop, behind the scenes python calls inFile.next() repeatedly until it reaches EOF. Looping it again doesn't reset the counter.
If you want to loop the content multiple times, you can read the whole content into memory by making it a python list of lines lines = inFile.readlines(), then you can loop over lines as many times as you want.
There are few different ways to achieve what you need here.
The current code will read all lines in the file, hence the file pointer (like a reading head scanning over the file) will be at the end after the first search.
Now, the thing is that file pointers do not reset automatically, that is, you must manually put it back at the beginning of the file.
The simplest way to fix your current code is to insert a file.seek(0) operation in the search() function, like this:
def main():
print("\nHello, welcome to Sales Data Menu.")
select=0
inFile = open("sales_data.csv", "r")
while select != 4:
select = int(input("\n1.)Search for an inovice item based on last name or id number.\n2.)Find and display the total number of items on the invoice.\n3.)Find and display the total cost of the invoice.\n4.)Exit the menu.\nEnter a number to select an option to do: "))
if select==1:
search(inFile)
else:
print("You did not enter a valid integer. Please re-enter")
inFile.close()
def search(inFile):
item = input("Enter a last name or an id number to search by.")
for lines in inFile:
if item in lines:
print(lines)
inFile.seek(0) # this resets the file pointer, so the next operation will start from the beginning of the file

How to read a specific line of a file to a variable in python using enumerate?

In python I have a small piece of code that takes an integer input and reads through a file, going to the line inputted and reading that line to a variable. However, when checking to make sure the correct thing was assigned to the variable, the number that was inputted by the user was assigned to the variable, not what was on the line.
I have looked through posts that are quite similar to this and have used those pieces of code to create this.
What I have so far is the following:
with open("accounts.txt") as f:
for i, line in enumerate(f):
if i == Access:
account = i
break
# 'Access' is an integer, such as 1
# print(account) returns that integer rather than the string on that line in the file
The answer is probably very obvious and I'm not seeing it, but all solutions would be appreciated.
print(account) returns that integer rather than the string on that line in the file because you are printing the iteration of the loop rather than the line itself.
You just need to replace account = i with account = line and you are read to go.
account = i should be account = line

Python conditional statement based on text file string

Noob question here. I'm scheduling a cron job for a Python script for every 2 hours, but I want the script to stop running after 48 hours, which is not a feature of cron. To work around this, I'm recording the number of executions at the end of the script in a text file using a tally mark x and opening the text file at the beginning of the script to only run if the count is less than n.
However, my script seems to always run regardless of the conditions. Here's an example of what I've tried:
with open("curl-output.txt", "a+") as myfile:
data = myfile.read()
finalrun = "xxxxx"
if data != finalrun:
[CURL CODE]
with open("curl-output.txt", "a") as text_file:
text_file.write("x")
text_file.close()
I think I'm missing something simple here. Please advise if there is a better way of achieving this. Thanks in advance.
The problem with your original code is that you're opening the file in a+ mode, which seems to set the seek position to the end of the file (try print(data) right after you read the file). If you use r instead, it works. (I'm not sure that's how it's supposed to be. This answer states it should write at the end, but read from the beginning. The documentation isn't terribly clear).
Some suggestions: Instead of comparing against the "xxxxx" string, you could just check the length of the data (if len(data) < 5). Or alternatively, as was suggested, use pickle to store a number, which might look like this:
import pickle
try:
with open("curl-output.txt", "rb") as myfile:
num = pickle.load(myfile)
except FileNotFoundError:
num = 0
if num < 5:
do_curl_stuff()
num += 1
with open("curl-output.txt", "wb") as myfile:
pickle.dump(num, myfile)
Two more things concerning your original code: You're making the first with block bigger than it needs to be. Once you've read the string into data, you don't need the file object anymore, so you can remove one level of indentation from everything except data = myfile.read().
Also, you don't need to close text_file manually. with will do that for you (that's the point).
Sounds more for a job scheduling with at command?
See http://www.ibm.com/developerworks/library/l-job-scheduling/ for different job scheduling mechanisms.
The first bug that is immediately obvious to me is that you are appending to the file even if data == finalrun. So when data == finalrun, you don't run curl but you do append another 'x' to the file. On the next run, data will be not equal to finalrun again so it will continue to execute the curl code.
The solution is of course to nest the code that appends to the file under the if statement.
Well there probably is an end of line jump \n character which makes that your file will contain something like xx\n and not simply xx. Probably this is why your condition does not work :)
EDIT
What happens if through the python command line you type
open('filename.txt', 'r').read() # where filename is the name of your file
you will be able to see whether there is an \n or not
Try using this condition along with if clause instead.
if data.count('x')==24
data string may contain extraneous data line new line characters. Check repr(data) to see if it actually a 24 x's.

edit a file line by line interactively from user input in python

I want to know how to edit a file on the fly row by row in python.
For example I have a text file where I usually have:
key value
key value
key value
key value
key value
...
they are not necessarily the same pair for each line. It's just the way I explained it.
I would like to show line by line key and value (on my terminal) and then I want to do one of this two things:
-just press enter (or whatever hot-key) to go ahead and read (show) next line.
-enter a new value then hit enter. this will actually replace the value (that was being shown) on the file and finally go ahead to show next pair of key values.
Till end of file or possibly till I type 'quit' or some other keyword. doesn't matter.
-Being able to go back to the previous row would be a plus (in case of accidentally going to next row), but it's not too important for now.
I find myself often editing huge files in a very tedious and repetitive way, and text editors are really frustrating with their cursors going everywhere when pressing the arrow-key. Also having to use the backspace to delete is annoying.
I know how to read a file and how to write a file in python. But not in such interactive way. I only know how to write the whole file at once. Plus I wouldn't know if it is safe to open the same file in both reading and writing. Also I know how to manipulate each line, split the text in a list of values etc... all I really need is to understand how to modify the file at that exact current line and handle well this type of interaction.
what is the best way to do this?
All the answers focus on loading the contents of the file in memory, modifying and then on close saving all on disk, so I thought I'd give it a try:
import os
sep = " "
with open("inline-t.txt", "rb+") as fd:
seekpos = fd.tell()
line = fd.readline()
while line:
print line
next = raw_input(">>> ")
if next == ":q":
break
if next:
values = line.split(sep)
newval = values[0] + sep + next + '\n'
if len(newval) == len(line):
fd.seek(seekpos)
fd.write(newval)
fd.flush()
os.fsync(fd)
else:
remaining = fd.read()
fd.seek(seekpos)
fd.write(newval + remaining)
fd.flush()
os.fsync(fd)
fd.seek(seekpos)
line = fd.readline()
seekpos = fd.tell()
line = fd.readline()
The script simply opens the file, reads line by line, and rewrites it if the user inputs a new value. If the length of the data matches previous data, seek and write are enough. If the new data is of different size, we need to clean-up after us. So the remainder of the file is read, appended to the new data, and everything is rewritten to disk. fd.flush and os.fsync(fd) guarantee that changes are indeed available in the file as soon as it is written out. Not the best solution, performance-wise, but I believe this is closer to what he asked.
Also, consider there might be a few quirks in this code, and I'm sure there's room for optimizing -- perhaps one global read at the beggining to avoid multiple whole file reads if changes that need adjusting are made often, or something like that.
The way I would go about this is to load all the lines of the text file in a list, and then iterate through that list, changing the values of the list as you go along. Then at the very end (when you get to the last line or whenever you want), you will write that whole list out to the file with the same name, so that way it will overwrite the old file.

Why doesn't this simple search work?

am simply iterating through an external file (which contains a phrase) and want to see if a line exists (which has the word 'Dad' in it) If i find it, I want to replace it with 'Mum'. Here is the program i've built... but am not sure why it isn't working?!
message_file = open('test.txt','w')
message_file.write('Where\n')
message_file.write('is\n')
message_file.write('Dad\n')
message_file.close()
message_temp_file = open('testTEMP.txt','w')
message_file = open('test.txt','r')
for line in message_file:
if line == 'Dad': # look for the word
message_temp_file.write('Mum') # replace it with mum in temp file
else:
message_temp_file.write(line) # else, just write the word
message_file.close()
message_temp_file.close()
import os
os.remove('test.txt')
os.rename('testTEMP.txt','test.txt')
This should be so simple...it's annoyed me! Thanks.
You don't have any lines that are "Dad". You have a line that is "Dad\n", but no "Dad". In addition, since you've done message_file.read(), the cursor is at the end of your file so for line in message_file will return StopIteration immediately. You should do message_file.seek(0) just before your for loop.
print(message_file.read())
message_file.seek(0)
for line in message_file:
if line.strip() == "Dad":
...
That should put the cursor back at the beginning of the file, and strip out the newline and get you what you need.
Note that this exercise is a great example of how not to do things in general! The better implementation would have been:
in_ = message_file.read()
out = in_.replace("Dad","Mum")
message_temp_file.write(out)
print(message_file.read())
here you already read the whole file.
Nothing is left for the for loop to check
A file object always remembers where it stopped to read/write the last time you accessed it.
So if you call print(message_file.readline()), the first line of the file is read and printed. Next time you call the same command, the second line is read and printed and so on until you reach the end of the file. By using print(message_file.read()) you have read the whole file and any further call of read or readline will give you nothing
You can get the current position by message_file.tell() and set it to a certain value by message_file.seek(value), or simply reopen the file
The problem most likely is due to the fact that your conditional will only match the string "Dad", when the string is actually "Dad\n". You could either update your conditional to:
if line == "Dad\n":
OR
if "Dad" in line:
Lastly, you also read the entire file when you call print(message_file.read()). You either need to remove that line, or you need to put a call to message_file.seek(0) in order for the loop that follows to actually do anything.

Categories

Resources