Maths quiz for python - str object has no attribute - python

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.

Related

Assigning a variable from a different file with a string

In the file values there are a bunch of lists and I want to assign gun_type to a value depending on what my current_gun_name is plus the string _Iron.
How do I do this? This is my current code but it doesnt work
current_gun_name = string_assigned_above
iron = win32api.GetAsyncKeyState(0x67)
if iron < KeyMin and win32api.GetAsyncKeyState(0x11) < 0:
gun_type = values.(current_gun_name + "_Iron")
So, on the last line there I am trying to pull a list from another file called values. But the list that I am trying to pull depends on the current_gun_name string. For example:
current_string = "test"
list_from_values = values.(current_gun_name + "ing")
print(list_from_values)
In this code it should find a list in the file called values. The list it will find and print will be called "testing" as I am asking it to use the variable plus "ing" Except this doesnt work

Fastest Way To Run Through 50k Lines of Excel File in OpenPYXL

I'm using openpyxl in python, and I'm trying to run through 50k lines and grab data from each row and place it into a file. However.. what I'm finding is it runs incredibely slow the farther I get into it. The first 1k lines goes super fast, less than a minute, but after that it takes longer and longer and longer to do the next 1k lines.
I was opening a .xlsx file. I wonder if it is faster to open a .txt file as a csv or something or to read a json file or something? Or to convert somehow to something that will read faster?
I have 20 unique values in a given column, and then values are random for each value. I'm trying to grab a string of the entire unique value column for each value.
Value1: 1243,345,34,124,
Value2: 1243,345,34,124,
etc, etc
I'm running through the Value list, seeing if the name exists in a file, if it does, then it will access that file and append to it the new value, if the file doesn't exist, it will create the file and then set it to append. I have a dictionary that has all the "append write file" things connected to it, so anytime I want to write something, it will grab the file name, and the append thing will be available in the dict, it will look it up and write to that file, so it doesn't keep opening new files everytime it runs.
The first 1k took less than a minute.. now I'm on 4k to 5k records, and it's running all ready 5 minutes.. it seems to take longer as it goes up in records, I wonder how to speed it up. It's not printing to the console at all.
writeFile = 1
theDict = {}
for row in ws.iter_rows(rowRange):
for cell in row:
#grabbing the value
theStringValueLocation = "B" + str(counter)
theValue = ws[theStringValueLocation].value
theName = cell.value
textfilename = theName + ".txt"
if os.path.isfile(textfilename):
listToAddTo = theDict[theName]
listToAddTo.write("," + theValue)
if counter == 1000:
print "1000"
st = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
else:
writeFileName = open(textfilename, 'w')
writeFileName.write(theValue)
writeFileName = open(textfilename, 'a')
theDict[theName] = writeFileName
counter = counter + 1
I added some time stamps to the above code, it is not there, but you can see the output below. The problem I'm seeing is that it is going up higher and higher each 1k run. 2 minutes the firs ttime, thne 3 minutes, then 5 minutes, then 7 minutes. By the time it hits 50k, I'm worried it's going to be taking an hour or something and it will be taking too long.
1000
2016-02-25 15:15:08
20002016-02-25 15:17:07
30002016-02-25 15:20:52
2016-02-25 15:25:28
4000
2016-02-25 15:32:00
5000
2016-02-25 15:40:02
6000
2016-02-25 15:51:34
7000
2016-02-25 16:03:29
8000
2016-02-25 16:18:52
9000
2016-02-25 16:35:30
10000
Somethings I should make clear.. I don't know the names of the values ahead of time, maybe I should run through and grab those in a seperate python script to make this go faster?
Second, I need a string of all values seperated by comma, that's why I put it into a text file to grab later. I was thinking of doing it by a list as was suggested to me, but I'm wondering if that will have the same problem. I'm thinking the problem has to do with reading off excel. Anyway I can get a string out of it seperated by comma, I can do it another way.
Or maybe I could do try/catch instead of searching for the file everytime, and if there is an error, I can assume to create a new file? Maybe the lookup everytime is making it go really slow? the If the file exists?
this question is a continuation from my original here and I took some suggestions from there.... What is the fastest performance tuple for large data sets in python?
I think what you're trying to do is get a key out of column B of the row, and use that for the filename to append to. Let's speed it up a lot:
from collections import defaultdict
Value_entries = defaultdict(list) # dict of lists of row data
for row in ws.iter_rows(rowRange):
key = row[1].value
Value_entries[key].extend([cell.value for cell in row])
# All done. Now write files:
for key in Value_entries.keys():
with open(key + '.txt', 'w') as f:
f.write(','.join(Value_entries[key]))
It looks like you only want cells from the B-column. In this case you can use ws.get_squared_range() to restrict the number of cells to look at.
for row in ws.get_squared_range(min_col=2, max_col=2, min_row=1, max_row=ws.max_row):
for cell in row: # each row is always a sequence
filename = cell.value
if os.path.isfilename(filename):
…
It's not clear what's happening with the else branch of your code but you should probably be closing any files you open as soon as you have finished with them.
Based on the other question you linked to, and the code above, it appears you have a spreadsheet of name - value pairs. The name in in column A and the value is in column B. A name can appear multiple times in column A, and there can be a different value in column B each time. The goal is to create a list of all the values that show up for each name.
First, a few observations on the code above:
counter is never initialized. Presumably it is initialized to 1.
open(textfilename,...) is called twice without closing the file in between. Calling open allocates some memory to hold data related to operating on the file. The memory allocated for the first open call may not get freed until much later, maybe not until the program ends. It is better practice to close files when you are done with them (see using open as a context manager).
The looping logic isn't correct. Consider:
First iteration of inner loop:
for cell in row: # cell refers to A1
valueLocation = "B" + str(counter) # valueLocation is "B1"
value = ws[valueLocation].value # value gets contents of cell B1
name = cell.value # name gets contents of cell A1
textfilename = name + ".txt"
...
opens file with name based on contents of cell A1, and
writes value from cell B1 to the file
...
counter = counter + 1 # counter = 2
But each row has at least two cells, so on the second iteration of the inner loop:
for cell in row: # cell now refers to cell B1
valueLocation = "B" + str(counter) # valueLocation is "B2"
value = ws[valueLocation].value # value gets contents of cell B2
name = cell.value # name gets contents of cell B1
textfilename = name + ".txt"
...
opens file with name based on contents of cell "B1" <<<< wrong file
writes the value of cell "B2" to the file <<<< wrong value
...
counter = counter + 1 # counter = 3 when cell B1 is processed
Repeat for each of 50K rows. Depending on how many unique values are in column B, the program could be trying to have hundreds or thousands of open files (based on contents of cells A1, B1, A2, B2, ...) ==>> very slow or program crashes.
iter_rows() returns a tuple of the cells in the row.
As people suggested in the other question, use a dictionary and lists to store the values and write them all out at the end. Like so (Im using python 3.5, so you may have to adjust this if you are using 2.7)
Here is a straight forward solution:
from collections import defaultdict
data = defaultdict(list)
# gather the values into lists associated with each name
# data will look like { 'name1':['value1', 'value42', ...],
# 'name2':['value7', 'value23', ...],
# ...}
for row in ws.iter_rows():
name = row[0].value
value = row[1].value
data[name].append(value)
for key,valuelist in data.items():
# turn list of strings in to a long comma-separated string
# e.g., ['value1', 'value42', ...] => 'value1,value42, ...'
value = ",".join(valuelist)
with open(key + ".txt", "w") as f:
f.write(value)

Python - 'str' object has no attribute 'append'

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.

Python, AttributeError: 'float' object has no attribute 'encode'

I have a script which consumes an API of bus location, I am attempting to parse the lat/lng fields which are float objects. I am repeatedly receiving this error.
row.append(Decimal(items['longitude'].encode('utf-16')))
AttributeError: 'float' object has no attribute 'encode'
# IMPORTS
from decimal import *
#Make Python understand how to read things on the Internet
import urllib2
#Make Python understand the stuff in a page on the Internet is JSON
import simplejson as json
from decimal import Decimal
# Make Python understand csvs
import csv
# Make Python know how to take a break so we don't hammer API and exceed rate limit
from time import sleep
# tell computer where to put CSV
outfile_path='C:\Users\Geoffrey\Desktop\pycharm1.csv'
# open it up, the w means we will write to it
writer = csv.writer(open(outfile_path, 'wb'))
#create a list with headings for our columns
headers = ['latitude', 'longitude']
#write the row of headings to our CSV file
writer.writerow(headers)
# GET JSON AND PARSE IT INTO DICTIONARY
# We need a loop because we have to do this for every JSON file we grab
#set a counter telling us how many times we've gone through the loop, this is the first time, so we'll set it at 1
i=1
#loop through pages of JSON returned, 100 is an arbitrary number
while i<100:
#print out what number loop we are on, which will make it easier to track down problems when they appear
print i
#create the URL of the JSON file we want. We search for 'egypt', want English tweets,
#and set the number of tweets per JSON file to the max of 100, so we have to do as little looping as possible
url = urllib2.Request('http://api.metro.net/agencies/lametro/vehicles' + str(i))
#use the JSON library to turn this file into a Pythonic data structure
parsed_json = json.load(urllib2.urlopen('http://api.metro.net/agencies/lametro/vehicles'))
#now you have a giant dictionary.
#Type in parsed_json here to get a better look at this.
#You'll see the bulk of the content is contained inside the value that goes with the key, or label "results".
#Refer to results as an index. Just like list[1] refers to the second item in a list,
#dict['results'] refers to values associated with the key 'results'.
print parsed_json
#run through each item in results, and jump to an item in that dictionary, ex: the text of the tweet
for items in parsed_json['items']:
#initialize the row
row = []
#add every 'cell' to the row list, identifying the item just like an index in a list
#if latitude is not None:
#latitude = str(latitude)
#if longitude is not None:
#longitude = str(longitude)
row.append(Decimal(items['longitude'].encode('utf-16')))
row.append(Decimal(items['latitude'].encode('utf-16')))
#row.append(bool(services['predictable'].unicode('utf-8')))
#once you have all the cells in there, write the row to your csv
writer.writerow(row)
#increment our loop counter, now we're on the next time through the loop
i = i +1
#tell Python to rest for 5 secs, so we don't exceed our rate limit
sleep(5)
encode is available only for string. In your case item['longitude'] is a float. float doesn't have encode method. You can type case it and then use encode.
You can write like,
str(items['longitude']).encode('utf-16')
str(items['latitude']).encode('utf-16')
I think you can't pass an encoded string to Decimal object.
encode is a method that strings have, not floats.
Change row.append(Decimal(items['longitude'].encode('utf-16'))) to row.append(Decimal(str(items['longitude']).encode('utf-16'))) and similar with the other line.

Update: Python average income reading and writing files

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.

Categories