I have a function which works out whether or not the file is in a n x n square matrix i.e. 3x3 or 4x4. Now if I call the function it works fine; it says whether or not it is a nxn square.
My problem is I want to use an exception, if the function returns a False value, then it wont load the text file but give a error saying to ensure the file has a nxn grid.
So for example if I have the grid stored in a text file and I try to load it with python code; the program should keep looping until the file is in the correct format. I wasn't sure if there was an exception for a function boolean
ABC
DEF
GHI
J
Currently I have
def grid(n):
rows = len(n)
for row in n:
if len(row) != rows:
return False
Similar to how the file open works; if it doesn't exist (FileNotFoundError) then it'll keep looping until it finds the input file name
Here's one way to do it. Simply raise an appropriate exception if square(d) returns False.
#Return True if sq is square, False otherwise
def square(sq):
rows = len(sq)
return all(len(row) == rows for row in sq)
def loaddata():
while True:
try:
filename = input("Enter the name of the file to open: ") + ".txt"
with open(filename, "r") as f:
d = []
for line in f:
splitLine = line.split()
d.append(splitLine)
if not square(d):
raise ValueError
break
except FileNotFoundError:
print("File name does not exist; please try again")
except ValueError:
print("The format is incorrect")
for line in d:
print("".join(line))
We reset d to [] each time through the loop in case we need to get rid of the contents of a previous file that isn't square.
You're confusing handing the exception (the "except" statement) with raising one. What you should do in square is raise an exception instead of returning false and then handle it in your main program:
def square(sq):
rows = len(sq)
for row in sq:
if len(row) != rows:
raise ValueError("the format is incorrect")
def loaddata():
while True:
try:
filename=input("Enter the name of the file to open: ") + ".txt"
with open(filename,"r") as f:
for line in f:
splitLine=line.split()
d.append(splitLine)
break
square(d)
except FileNotFoundError:
print("File name does not exist; please try again")
except ValueError:
print("The format is incorrect")
for line in d:
print("".join(line))
return
Related
I'm trying to print integers from a file where each line has 1 integer, as well as print their sum. Everything seems to work fine, except when I enter the incorrect file name, loop back, and then enter the correct one. The program still outputs the correct information but then the error:
"AttributeError: 'NoneType' object has no attribute 'readline'". Why is this happening?
def main():
listnums = filetolist()
print(f'numbers in file: {listnums}')
print(f' sum of before mentioned numbers is: {sum(listnums)}')
# opens file
def openfile():
try:
file = open(input("what is the file named including the file extension?"), "r")
return file
except IOError:
tryagain = input("File could not be found \n" + "if you would like try again type 1 and press enter, to exit press enter")
if tryagain == "1":
main()
else:
exit()
# converts file to list
def filetolist():
file = openfile()
line = file.readline()
nums = []
linenumber = 1
while line != "":
nums += [verifyint(line, linenumber)]
line = file.readline()
linenumber += 1
file.close()
return nums
# verifies number is an int
def verifyint(num, linenumber):
try:
numint = int(num)
return numint
except ValueError:
print(f'Invalid value on line #{linenumber}')
exit()
main()
When you hit the except block, there is no return statement, so this function returns None after running main() again
Rather than effectively recurse, you should properly raise the errors and use a proper loop
def filetolist(filename):
with open(filename) as f:
return [int(line.rstrip()) for line in f]
def main():
while True:
filename = input("what is the file named including the file extension?")
try:
listnums = filetolist(filename)
print(f'numbers in file: {listnums}')
print(f' sum of before mentioned numbers is: {sum(listnums)}')
except ValueError, IOError:
again = input('Error! Try again? (y/n)')
if again.lower() != 'y':
break
main()
I think (i might be wrong) that the problem is that when you fail to read a file and try again you need to recall openfile and not the whole main.
If you call the whole main you are opening a new file doing all the routine and then returning nothing.
Try that And tell me if it works
def openfile():
try:
file = open(input("what is the file named including the file extension?"), "r")
return file
except IOError:
tryagain = input("File could not be found \n" + "if you would like try again type 1 and press enter, to exit press enter")
if tryagain == "1":
return openfile()
else:
exit()
here a screenshot
I want to catch several exceptions on the same line, but have different outcome depending on which exception is triggered. I'm trying to summarize a set of numbers in a text file and want to check on value and io errors.
try:
filex = open('test.txt', 'r')
number = filex.readline().rstrip('\n')
added = 0
while number != '':
added += int(number)
number = filex.readline().rstrip('\n')
print(added)
filex.close()
except (IOError,ValueError):
if IOError:
print('IOError')
else:
print('ValueError')
The issue I'm having is that it will always trigger on the first condition of the IF test.
can use two except for this condition like this
try
.......
except IOError:
print('IOError')
except ValueError:
print('ValueError')
I recommend using one clause per exception. Here is the "I'm stubborn" version:
try:
filex = open('test.txt', 'r')
number = filex.readline().rstrip('\n')
added = 0
while number != '':
added += int(number)
number = filex.readline().rstrip('\n')
print(added)
filex.close()
except (IOError,ValueError) as e:
if isinstance(e, IOError):
print('IOError')
else:
print('ValueError')
Here's the clause-per-exception version:
try:
filex = open('test.txt', 'r')
number = filex.readline().rstrip('\n')
added = 0
while number != '':
added += int(number)
number = filex.readline().rstrip('\n')
print(added)
filex.close()
except IOError:
print('IOError')
except ValueError:
print('ValueError')
You can see that in the first version, you have to implement type checking, which Python's exception handling would otherwise give you for free. And the second version is slightly shorter, too.
if IOError:
I think this line checks the trueness of the class IOError. It ignores the type of error that was raised.
You could maybe do something like :
except (IOError, ValueError) as e:
if instanceof(e, IOError):
#...
So I am working on doing a "simple" task since like 2h and still can't find the solution, so where is my question :
I want to search in a file, line by line, and if no result is found, at the end print something, else call a function.
def DeletItemCheckUp():
import re
find = True
itemNumber = input("\n what is the item you want to delet : ")
fileItem = open('Data_Item', 'r', encoding='Utf-8')
for line in fileItem:
sr = re.search(r'^\b%s\b'%itemNumber,(line.split(';')[0]))
if (sr == None):
pass
print("This item don't exist.")
fileItem.close()
if (find == True):
return itemNumber
DeletItem()
so here is the problem I have got with different try :
1. Print "This item don't exist." for every line that didn't had my itemNumber.
2. When there was actually no match found, its would not call DeletItem().
objectif of the code :
Ask for a item to delet, check in a file if the unique item number exist, if so, call DeletItem() to delet it, else, tell the user that this unique item number don't exist.
Few overlooks in there to achieve what you ask. We are going to use a flag (true/false) to know when we found something, and based on that we will decide whether to call the function or print/return the number.
def DeletItemCheckUp():
import re
find = False # initialize to False
itemNumber = input("\n what is the item you want to delet : ")
fileItem = open('Data_Item', 'r', encoding='Utf-8')
for line in fileItem:
sr = re.search(r'^\b%s\b'%itemNumber,(line.split(';')[0]))
if (sr == None):
continue # do nothing and continue
else:
# we found the number, set the flag and break
find = True
break # no need to continue searching
fileItem.close()
if (find):
DeletItem() # call the function
else:
print("This item don't exist.")
1) replace the pass with your print('This item doesn't exist'). "Pass" means "do nothing."
2) Your DeleteItem() is after the return. Nothing executes after the return because you have returned to the place the function was called from. You want
else:
DeleteItem()
while True:
try:
OpenFile=raw_input(str("Please enter a file name: "))
infile=open(OpenFile,"r")
contents=infile.readlines()
infile.close()
user_input = raw_input(str("Enter A=<animal> for animal search or B=<where lives?> for place of living search: \n"))
if user_input.startswith("A="):
def find_animal(user_input,column):
return next(("\t".join(line) for line in contents
if line[column-1]==user_input),None)
find_animal(user_input[1:])
print str((find_animal(user_input[1:], "WHO?"))) #"Who?" is the name of the first column.
else:
print "Unknown option!"
except IOError:
print "File with this name does not exist!"
1.Enter the name of an animal.
2.Program searches for the lines that have this particular name in the first column.
3.Program prints lines that have this name in the first column.
My function can't seem to work properly here. Can you please help me find the mistake(s)? Thank you!
EDIT
def ask_for_filename():
filename=str(raw_input("Please enter file name: "))
return filename
def read_data(filename):
contents=open(filename,"r")
data=contents.read()
return data
def column_matches(line, substring, which_column):
for line in data:
if column_matches(line, substring, 0):
print line
Big chunks of code are hard to read and debug, try splitting your code into smaller functions, for example like this:
def ask_for_filename():
#left as an exercise
return filename
def read_data(filename):
#left as an exercise
return data
def column_matches(line, substring, which_column):
#left as an exercise
def show_by_name(name, data):
for line in data:
if column_matches(line, name, 0):
print line
def do_search(data):
propmt = "Enter A=<animal> for animal search or B=<where lives?> for place of living search: \n"
user_input = raw_input(prompt)
if user_input.startswith('A='):
show_by_name(user_input[2:], data)
# main program
filename = ask_for_filename()
data = read_data(filename)
while True:
do_search(data)
Test and debug these functions separately until you're sure they work properly. Then write and test the main program.
column_matches() is supposed to return true if some column (which_column) in a line is equal to substring. For example, column_matches("foo\tbar\tbaz", "bar", 1) is True. To achieve that
split a line by a delimiter - this gives us a list of values
get the n-th element of the list
compare it with the substing
return True if they are equal and False otherwise
Putting it all together:
def column_matches(line, substring, which_column):
delimiter = '\t'
columns = line.split(delimiter)
value = columns[which_column]
if value == substring:
return True
else:
return False
or, in a more concise and "pythonic" form:
def column_matches(line, substring, which_column):
return line.split('\t')[which_column] == substring
I have been trying different ways of writing this code but cannot get past this. Currently the program will run all the way to the write_names(list) function and create the file, and the print function will print the sorted list. The program refuses to get the user input for the search_names() function but it will print anything I ask it to.
Debug highlights: while index < len(list) and in the debug I\O only states "read file error". Hopefully someone has an idea what I'm doing wrong.
'# Abstract: This program creates a list of names. The list is printed,
'# sorted, printed again, written to file, and searched.
'#=============================================================================
'#define the main function
def main():
#try:
##open data file for read
#infile = open('names.txt', 'r')
#call get_names function
list = get_names()
#call print function
print_names(list)
#sort list
list.sort()
#print sorted list
print_names(list)
#write sorted list to new file
write_names(list)
#allow user to search list
search_names(list)
def get_names():
try:
infile = open('names.txt', 'r')
#read file contents into a list
list = infile.readlines()
#close file
infile.close()
#strip \n from each element
index = 0
while index < len(list):
list[index] = list[index].rstrip('\n')
index += 1
return list
except IOError:
print 'Read file error'
def print_names(list):
#print header
print '******************'
#print list line by line
index = 0
while index < len(list):
print list[index]
index += 1
return
def write_names(list):
#open file for writing
outfile = open('sortedNames.txt', 'w')
#write the list to the file
for item in list:
outfile.write(str(item) + '\n')
#close file
outfile.close()
def search_names(list):
#set user test variable
again = 'Y'
while again.upper == 'Y':
#get search from user
search = raw_input('Enter a name to search for: ')
#open list for search
if search in list:
try:
item_index = list.index(search)
print search, 'found.', item_index
except ValueError:
print search, 'not found.'
main()
'
Thanks in advance!
Your issue is that upper is a function, and you are not calling it. Your while in search_names() should read:
while again.upper() == 'Y':
instead of:
#strip \n from each element
index = 0
while index < len(list):
list[index] = list[index].rstrip('\n')
index += 1
return list
just use this list comprehension:
lines = infile.readlines()
infile.close()
return [ line.strip() for line in lines ]
edit:
It looks like you are using an index and a while loop where a for loop can be used.
Instead of:
while index < len(list):
print list[index]
index += 1
use:
# using name_list instead of list
for name in name_list:
print name
also, your search_names() function looks flawed:
def search_names(list):
#set user test variable
again = 'Y'
while again.upper == 'Y':
#get search from user
search = raw_input('Enter a name to search for: ')
#open list for search
if search in list:
try:
item_index = list.index(search)
print search, 'found.', item_index
except ValueError:
print search, 'not found.'
would never exit (again is never reassigned). try:
def search_names(names_list):
again = 'Y'
while again.upper() == 'Y':
s_name = raw_input('Enter a name to search for: ')
if s_name in names_list:
print s_name, 'found.', names_list.index(s_name)
else:
print search, 'not found.'
again = raw_input('Search for another name (Y|N)?: ')
or:
def search_names(names_list):
again = 'Y'
while again == 'Y':
s_name = raw_input('Enter a name to search for: ')
try:
idx = names_list.index(s_name)
print s_name, 'found.', idx
except ValueError:
print search, 'not found.'
again = raw_input('Search for another name (Y|N)?: ').upper()
Which brings up the issue of when to catch exceptions vs using an if statement:
from msdn:
The method you choose depends on how
often you expect the event to occur.
If the event is truly exceptional and
is an error (such as an unexpected
end-of-file), using exception handling
is better because less code is
executed in the normal case. If the
event happens routinely, using the
programmatic method to check for
errors is better. In this case, if an
exception occurs, the exception will
take longer to handle.
Comments begin with #, not '# - you are making every other line of your header a docstring.
You are using an index to iterate across lists, which is inefficient - just iterate on the list items.
Calling a variable list is bad because it prevents you from accessing the list() datatype.
Using with is a more reliable replacement for open() .. close()
again.upper is a function reference - you have to call the function, ie again.upper().
You never change the value of again - this will be an infinite loop!
You test if search in list but then do a try..except block which will only fail if it is not in the list (ie you are testing for the same failure twice).
.
#
# Operate on a list of names
#
def load_names(fname):
try:
with open(fname, 'r') as inf:
return [line.strip() for line in inf]
except IOError:
print "Error reading file '{0}'".format(fname)
return []
def print_names(namelist):
print '******************'
print '\n'.join(namelist)
def write_names(namelist, fname):
with open(fname, 'w') as outf:
outf.write('\n'.join(namelist))
def search_names(namelist):
while True:
lookfor = raw_input('Enter a name to search for (or nothing to quit): ').strip()
if lookfor:
try:
ind = namelist.index(lookfor)
print("{0} found.".format(lookfor))
except ValueError:
print("{0} not found.".format(lookfor))
else:
break
def main():
namelist = load_names('names.txt')
print_names(namelist)
namelist.sort()
print_names(namelist)
write_names(namelist, 'sorted_names.txt')
search_names(namelist)
if __name__=="__main__":
main()