I've searched this error on here, but haven't seen anything that yet matches my situation (disclaimer, I'm still getting used to Python).
import os
os.chdir("C:\Projects\Rio_Grande\SFR_Checking") # set working directory
stressPeriod = 1
segCounter = 1
inFlow = 0
outFlow = 0
with open(r"C:\Projects\streamflow.dat") as inputFile:
inputList = list(inputFile)
while stressPeriod <= 1:
segCounter = 1
lineCounter = 1
outputFile = open("stats.txt", 'w') # Create the output file
for lineItem in inputList:
if (((stressPeriod - 1) * 11328) + 8) < lineCounter <= (stressPeriod * 11328):
lineItem = lineItem.split()
if int(lineItem[3]) == int(segCounter) and int(lineItem[4]) == int(1):
inFlow = lineItem[5]
outFlow = lineItem[7]
lineItemMem = lineItem
elif int(lineItem[3]) == int(segCounter) and int(lineItem[4]) <> int(1):
outFlow = lineItem[7]
else:
gainLoss = str(float(outFlow) - float(inFlow))
lineItemMem.append(gainLoss)
lineItemMem = ','.join(lineItemMem)
outputFile.write(lineItemMem + "\n") # write # lines to file
segCounter += 1
inFlow = lineItem[5]
outFlow = lineItem[7]
lineCounter += 1
outputFile.close()
So basically this program is supposed to read a .dat file and parse out bits of information from it. I split each line of the file into a list to do some math on it (math operations are between varying lines in the file, which adds complexity to the code). I then append a new number to the end of the list for a given line, and that's where things inexplicably break down. I get the following error:
Traceback (most recent call last):
File "C:/Users/Chuck/Desktop/Python/SFR/SFRParser2.py", line 49, in <module>
lineItemMem.append(gainLoss)
AttributeError: 'str' object has no attribute 'append'
When I give it a print command to test that lineItemMem is actually a list and not a string, it prints a list for me. If I put in code for
lineItemMem.split(",") to break the string, I get an error saying that list object has no attribute split. So basically, when I try to do list operations, the error says its a string, and when I try to do string operations, the error says it's a list. I've tried a fair bit of mucking around, but frankly can't tell what the problem is here. Any insight is appreciated, thanks.
I think the issue has to do with these lines:
lineItemMem.append(gainLoss)
lineItemMem = ','.join(lineItemMem)
Initially lineItemMem is a list, and you can append an item to the end of it. However, the join call you're doing turns the list into a string. That means the next time this part of the code runs, the append call will fail.
I'm not certain exactly what the best solution is. Perhaps you should use a different variable for the string version? Or maybe after you join the list items together into a single string and write that result out, you should reinitialize the lineItemMem variable to a new empty list? You'll have to decide what works best for your actual goals.
There are two places where lineItemMem is set. The first is this:
lineItem = lineItem.split()
# ...
lineItemMem = lineItem
where it is set to the result of a split operation, i.e. a List.
The second place is this:
lineItemMem = ','.join(lineItemMem)
here, it is set to the result of a join operation, i.e. a String.
So, the reason why the error sometimes states that it is a string and sometimes a list is, that that is acutally the case depending on the conditions in the if statement.
The code, as presented, is imho near undebuggable. Instead of tinkering, it would be a better approach to think about the different goals that should be achieved (reading a file, parsing the content, formatting the data, writing it to another file) and tackle them individually.
Related
Intro:
I'm a beginner python learning syntax at the moment. I've come across this concept of reading and writing files natively supported by python. I've figured to give it a try and find bugs after attempting looping reading and writing commands. I wanted to randomly pick a name from a name file and then writing it into a new file. My file includes 19239 lines of names, randrange(18238) generates from 0 - 18238, and, supposedly, would read a randomly read a line between 1 - 18239. The problem is that the code that reads and writes works without the for loop but not with the for loop.
My attempt:
from random import randrange
rdname = open("names.dat", "r")
wrmain = open("main.dat", "a")
rdmain = open("main.dat", "r")
for x in range(6):
nm = rdname.readlines()[randrange(18238)]
print(str(randrange(18238)) + ": " + nm)
wrmain.write("\n" + nm)
...
Error code:
Exception has occurred: IndexError
list index out of range
Good luck with your programming journey.
The readlines() method. Has some non-intuitive behaviour. When you use the readlines() it "dumps" the entire content of the file and returns a list of strings of each line. Thus the second time you call the rdname.readlines()[randrange(18238)], the rdname file object is completely empty and you actually have an empty list. So functionally you are telling your programme to run [][randrange(18238)] on the second iteration of the loop.
I also took the liberty of fixing the random number call, as the way you had implemented it would mean it would call 2 different random numbers when selecting the name nm = rdname.readlines()[randrange(18238)] and printing the selected name and linenumber print(str(randrange(18238)) + ": " + nm)
...
rdname = open("names.dat", "r")
wrmain = open("main.dat", "a")
rdmain = open("main.dat", "r")
rdname_list = rdname.readlines()
for x in range(6):
rd_number = randrange(18238)
nm = rdname_list[rd_number]
print(str(rd_number) + ": " + nm)
wrmain.write("\n" + nm)
...
rdname.readlines() exhausts your file handle. Running rdname.readlines() gives you the list of lines the first time, but returns an empty list every subsequent time. Obviously, you can't access an element in an empty list. To fix this, assign the result of readlines() to a variable just once, before your loop.
rdlines = rdname.readlines()
maxval = len(rdlines)
for x in range(6):
randval = randrange(maxval)
nm = rdlines[randval]
print(str(randval) + ": " + nm)
wrmain.write("\n" + nm)
Also, making sure your random number can only go to the length of your list is a good idea. No need to hardcode the length of the list though -- the len() function will give you that.
I highly recommend you take a look at how to debug small programs. Using a debugger to step through your code is immensely helpful because you can see how each line affects the values of your variables. In this case, if you'd looked at the value of nm in each iteration, it would be obvious why you got the IndexError, and finding out that nm becomes an empty list on readlines() would point you in the direction of the answer.
Exporting the data:
num = 0
exportData = open("results_file.txt", "a")
while num < len(runs) - 1:
exportData.write(str(runs[num]) + "\n")
num = num + 1
exportData.close()
Importing the data into the new file:
runs = []
num = 1
count = len(open("results_file.txt").readlines( ))
print(count)
importData = open("results_file.txt", "r")
while num < count:
runs.append(importData.read(num))
print(importData.read(num))
num = num + 1
importData.close()
My goal is to export the array of integers to a file (can be something else than a txt file for all I care) and then to import them at a later date into a new file and use them there as integers (performing mathematical operations on them)
The error that I'm getting (on line 28 I'm trying to use the first number in the array for a mathematical calculation):
line 28, in if runs[num] < 7: TypeError: '<' not supported between instances of 'str' and 'int'
runs = []
num = 1
count = len(open("results_file.txt").readlines( ))
print(count)
importData = open("results_file.txt", "r")
while num < count:
runs.append(int(importData.read(num)))
print(importData.read(num))
num = num + 1
importData.close()
Adding int() returns this error:
ValueError: invalid literal for int() with base 10: '4\n1'
You're not being pythonic, and many of the answers here aren't either. So, let me clean up your code a bit.
from ast import literal_eval
with open("results_file.txt", "a") as exportData:
for run in runs:
exportData.write(str(run) + "\n")
runs = []
with open("results_file.txt", "r") as importData:
runs.extend([literal_eval(x) for x in importData])
I'll break this down line by line:
from ast import literal_eval is the safest way to parse things that are strings into python objects. It's better than using a plain old eval because it won't run arbitrary code. We'll use this function to read the data latter.
with open(...) as ... is the best way to open a file. It contains the file-object within a single scope and catches errors. Look this one up here: Pep 343
for ... in ... For loops that you're using are not pythonoic at all. The pythonic way is to use iterators no need to count lines and declare variables to keep track... the python objects keep track of themselves. (If you need a counter I highly recommend that you look up enumerate() Enumerate() in Python
exportData.write(str(run) + "\n") only change here is that with the pythonic for loop there's no need to index the runs list anymore.
runs = [] I think you know what this is, but I have to declare it out of the with statement because if the with statement throws an error, and you were to catch it, runs will be initialized.
I've already discussed with statements.
runs.extend([literal_eval(x) for x in importData]) Has two things going on. extend appends a list to a list... cool. The more interesting part here is the list comprehension. Here's a tutorial on list comprehensions. As soon as you get comfortable with the for loops, the list comprehension is the next pythonic step. For further pythonic enlightenment, this line could also be replaced with: runs.extend(map(literal_eval, importData))
That's it, 9 lines. Happy hacking.
The error you are experiencing is most likely due to the fact you're trying to add a string to an integer. Try doing
runs = []
num = 1
count = len(open("results_file.txt").readlines( ))
print(count)
importData = open("results_file.txt", "r")
while num < count:
runs.append(int(importData.read(num)))
print(importData.read(num))
num = num + 1
importData.close()
The main function/tool you're looking for is int(). For example:
>>> int('15')
15
>>> int('15') + 5
20
But you also can save yourself some real headaches by coding this differently. For example, you do not need to know the number of lines ahead of time. You can just call .readline() until it returns an empty string. Or even iterate over the file and when it ends, it with exit.
Another tip, and this is just good practice, is to use the context manager for opening files. So instead of
file = open('myfile.txt')
for line in file:
print(line)
you would do:
with open('myfile.txt') as file:
for line in file:
print(line)
The big advantage of the latter is that if will always make sure file is closed properly. This is especially helpful when writing to a file.
The first run-through of the while loop goes fine:
hour_count = list('00/')
hours = 0
while hours < 24: #loop while hours < 24
hour_count[1] = hours #<- error occurs on this line
hour_count = ''.join(hour_count) #convert to string
...
hours += 1
However, upon the second loop, it gives a TypeError: 'str' object does not support item assignment. The purpose is to set a file path.
When you run this line hour_count = ''.join(hour_count), you're changing the data type of hour_count from a list to a string.
Because strings are immutable, you can't modify one character via the index notation (the line before this line attempts to do that).
I'm not totally sure what your goal is, but perhaps you're looking to append to the list. These docs will help with that.
https://docs.python.org/3.4/tutorial/datastructures.html
You changed the type;
# hour_count at this point is an array
hour_count[1] = hours
# The result of join is a string object
hour_count = ''.join(hour_count)
Next time through hour_count is a string and you can't do "string[1] = ..."
I've been assigned a task to log student scores for a maths quiz
Below is my task:
The teacher wants to use the results from students taking these quizzes to log their performance. The system should store >the last three scores for each student.
every time I run my code I receive the error:
AttributeError: 'str' object has no attribute 'append'
and when I convert into an int I get this error:
int() argument must be a string, a bytes-like object or a number, not 'NoneType'
import csv
import os
name = input("enter your name: ")
classroom_num = input("enter your classroom number: ")
score = 5
print ("%s, you scored %d/10 questions correctly"%(name,score))
status = open ("state.txt","w") #Every time program is run +1 is added, so that column 1-3 are updated
with open ("state.txt","r") as f:
state = f.read()
if os.stat("state.txt").st_size == 0:
status.write ("0")
state_ints = [ int(x) for x in state.split() ] #converts into int
addone = 1
if state_ints == 3: #If program is run more than 3 times the value in text file reset to 0
state_ints = 0
status.write (state_ints)
with open("Classroom {}.csv".format(classroom_num),"a+") as f:
rows = csv.reader(f)
for row in rows:
if row in rows in row[0] != (name) in row: #Checks if name exists in file (if so name isn't appended to column)
state_ints.append(addone) #Adds one everytime program is run so that score can be replaced for row 1-3
status.write (state_ints)
name_row = (row [0])
name_row.append(name)
score_row = (row (state_ints))
score_row.append(score)
else:
state_ints.append(addone)
status.write (state_ints)
score_row = (row [state_ints])
score_row.append(score)
status.close()
Also what other mistakes might I have made? What can I do to make this more efficient and complete this task?
A string is immutable. You can't change it. You need to make a new string or create a list and make a string of the list when you are done. Also int needs a string of a number to convert. A None type object is a variable with value None. int can't convert None to an integer so you get an error.
The line for row in ("Classroom {}.csv".format(classroom_num)): is iterating over a string, not a file. For each iteration, row is a single character string ('C' then 'l' etc).
row[0] is therefore the same as row and name_row.append(... is trying to call append on a string, hence the "'str' object has no attribute 'append'" error.
I can't see the int() call that's failing but the line state_ints = state_ints.append(addone) is setting state_ints to None. append modifies the list in place and returns None. You just want state_ints.append(addone).
There are several other problems as well that suggest you might want to review a tutorial
Putting a single item in brackets does nothing (an_object) is exactly the same as an_object.
row [state_ints] is trying to use a list as an index (assuming you didn't mean to set it to None
)
status.close should be a method call
if state_ints == 3: state_ints is a list at this point. It's never going to equal 3
etc
See what's going on here?
>>> for row in ("Classroom {}.csv".format("2")):
... print row
...
C
l
a
s
s
r
o
o
m
2
.
c
s
v
>>>
You're not actually opening the file called "Classroom[number].csv" but, instead, you're iterating the characters in the file name.
You can normally use append on the rows of a csv since they are typically transformed into lists (either manually via split(",") or via the csv module) but it fails here since your rows are, in fact, not rows/lists but characters/strings.
You can use with open and manually split by comma or use the csv module for parsing the file. The module approach:
>>> import csv
>>>
>>> with open("Classroom {}.csv".format(classroom_num),"r") as f:
... rows = csv.reader(f)
... for row in rows:
... print(row)
You keep re-using the file handle f when opening files. You also use both with open() and f = open (...). This means that you might be trying to open the same file twice, read from a file you've opened in "append"-mode or other confusing/conflicting actions. Simply stick to With open() - that way, you won't have to manually close the files either.
I was writing a code to find the average household income, and how many families are below poverty line.
this is my code so far
def povertyLevel():
inFile = open('program10.txt', 'r')
outFile = open('program10-out.txt', 'w')
outFile.write(str("%12s %12s %15s\n" % ("Account #", "Income", "Members")))
lineRead = inFile.readline() # Read first record
while lineRead != '': # While there are more records
words = lineRead.split() # Split the records into substrings
acctNum = int(words[0]) # Convert first substring to integer
annualIncome = float(words[1]) # Convert second substring to float
members = int(words[2]) # Convert third substring to integer
outFile.write(str("%10d %15.2f %10d\n" % (acctNum, annualIncome, members)))
lineRead = inFile.readline() # Read next record
# Close the file.
inFile.close() # Close file
Call the main function.
povertyLevel()
I am trying to find the average of annualIncome and what i tried to do was
avgIncome = (sum(annualIncome)/len(annualIncome))
outFile.write(avgIncome)
i did this inside the while lineRead. however it gave me an error saying
avgIncome = (sum(annualIncome)/len(annualIncome))
TypeError: 'float' object is not iterable
currently i am trying to find which household that exceeds the average income.
avgIncome expects a sequence (such as a list) (Thanks for the correction, Magenta Nova.), but its argument annualIncome is a float:
annualIncome = float(words[1])
It seems to me you want to build up a list:
allIncomes = []
while lineRead != '':
...
allIncomes.append(annualIncome)
averageInc = avgIncome(allIncomes)
(Note that I have one less indentation level for the avgIncome call.)
Also, once you get this working, I highly recommend a trip over to https://codereview.stackexchange.com/. You could get a lot of feedback on ways to improve this.
Edit:
In light of your edits, my advice still stands. You need to first compute the average before you can do comparisons. Once you have the average, you will need to loop over the data again to compare each income. Note: I advise saving the data somehow for the second loop, instead of reparsing the file. (You may even wish to separate reading the data from computing the average entirely.) That might best be accomplished with a new object or a namedtuple or a dict.
sum() and len() both take as their arguments an iterable. read the python documentation for more on iterables. you are passing a float into them as an argument. what would it mean to get the sum, or the length, of a floating point number? even thinking outside the world of coding, it's hard to make sense of that.
it seems like you need to review the basics of python types.