Serializing data with Google Protobuf in Python - python

I have a text file with contents like this (format ):
Alice:ECE505,56:HIS230,78:REC345,98
Bob:MATH300,78:IN121,79:LEC091,23:ARC,32:WER720,67
I would like to add each class name and score to its perspective person.
So far I have something like this:
all_stu = record_pb2.Result()
person = all_stu.student.add()
cl = person.courses.add()
with open(textfile, "r") as readfile:
txt = readfile.read()
for line in txt.split('\n'):
segment = line.split(':')
person.name = segment[0]
classes = segment[1:]
#I have tried this but it only returns the last class and score
for c in classes:
cname, score = c.split(',')
cl.name = cname
cl.score = score
I know my loop only returns the last class name and score but how do I store each of the classes and scores for the respective person/line with Google Protobuf? Thanks in advance!

You forget to add each each person you read from the file. Next you need to add each class your find in the person object. You now only create those objects once and thus you overwrite them all the time.
all_stu = record_pb2.Result()
person = all_stu.student.add()
with open(textfile, "r") as readfile:
txt = readfile.read()
for line in txt.split('\n'):
segment = line.split(':')
person = all_stu.student.add()
person.name = segment[0]
classes = segment[1:]
#I have tried this but it only returns the last class and score
for c in classes:
cl = person.courses.add()
cname, score = c.split(',')
cl.name = cname
cl.score = score
Here I do make the assumption that courses is a repeated field.

Related

Why does points not change to the users score and instead remains as the temporary value of 0?

points = "temp"
a = "temp"
f = "temp"
def pointincrementer():
global points
points = 0
for line in f:
for word in a:
if word in line:
scorelen = int(len(user+","))
scoreval = line[0:scorelen]
isolatedscore = line.replace(scoreval,'')
if "," in line:
scorestr = isolatedscore.replace(",","")
score = int(scorestr)
points = score + 1
print(points)
def score2():
f = open('test.txt','r')
a = [user]
lst = []
for line in f:
for word in a:
if word in line:
pointincrementer()
print(points)
point = str(points)
winning = (user+","+point+","+"\n")
line = line.replace(line,winning)
lst.append(line)
f.close()
f = open('test.txt','w')
for line in lst:
f.write(line)
f.close()
print("Points updated")
user = input("Enter username: ") #change so user = winners userid
with open('test.txt') as myfile:
if user in myfile.read():
score2()
else:
f = open('test.txt','r')
f2 = f.read()
f3 = (f2+"\n"+user)
f.close()
f = open('test.txt','w')
f.write(f3)
f.close()
score2()
This is paired with test.txt, which looks like this:
one,1,
two,5,
three,4,
four,94,
When this code is run, it it will ask the user their name (as expected) and then will print 0 (when it should instead print the user's score) and then Points updated. Anybody know how to sort this out?
There are many problems with your code. You should not be using global variables like that. Each function should be passed what it needs, do its computing, and return values for the caller to handle. You should not be reading the file multiple times. And you can't write the file while you still have it open with the with statement.
Here, I read the file at the beginning into a Python dictionary. The code just updates the dictionary, then writes it back out at the end. This makes for a simpler and more maintainable structure.
def readdata(fn):
data = {}
for row in open(fn):
info = row.strip().split(',')
data[info[0]] = int(info[1])
return data
def writedata(fn,data):
f = open(fn,'w')
for k,v in data.items():
print( f"{k},{v}", file=f )
def pointincrementer(data,user):
return data[user] + 1
def score2(data, user):
points = pointincrementer(data, user)
print(points)
data[user] = points
print("Points updated")
user = input("Enter username: ")
data = readdata( 'test.txt' )
if user not in data:
data[user] = 0
score2(data, user)
writedata( 'test.txt', data )
The f in pointincrementer() refers to the "temp" string declared on the third line. The f in score2() refers to the file handle declared immediately below the function header. To get around this, you can pass the file handle into pointincrementer():
def pointincrementer(file_handle):
global points
points = 0
for line in file_handle:
for word in a:
if word in line:
scorelen = int(len(user+","))
scoreval = line[0:scorelen]
isolatedscore = line.replace(scoreval,'')
if "," in line:
scorestr = isolatedscore.replace(",","")
score = int(scorestr)
points = score + 1
print(points)
def score2():
file_handle = open('test.txt','r')
a = [user]
lst = []
for line in f:
print(line)
for word in a:
if word in line:
pointincrementer(file_handle)
print(points)
point = str(points)
winning = (user+","+point+","+"\n")
line = line.replace(line,winning)
lst.append(line)
f.close()
f = open('test.txt','w')
for line in lst:
f.write(line)
f.close()
print("Points updated")
This leads to a parsing error. However, as you haven't described what each function is supposed to do, this is the limit to which I can help. (The code is also extremely difficult to read -- the lack of readability in this code snippet is likely what caused this issue.)

How to use elements in a list to create an object for a class

i've created a class containing the following constructor:
class Student:
def __init__(self, student_id, student_name, student_marks):
self.student_id = student_id
self.student_name = student_name
self.student_marks = student_marks
i'm accessing a text file that contains lines of text in the following format:
1,Harvey Specter,97
2,Mike Ross,84
3,Krimhilde Aust,94
first integer being student id, string being name and last integer being mark.
I would like to iterate over each line in the text file, convert it to a list and use the elements in the list to create an object for my class. So far I have this:\
with open('records.txt', 'r') as records:
for line in records:
line = line.replace(',',' ')
x = line.split()
x[1:3] = [' '.join(x[1:3])]
I would like to, over each iteration, create a new object for my class, something like this: (I know this is wrong)
x[0] = Student(x[0],x[1],x[2]
The problem here is in my variable. I need to (and I know this is wrong, please dont flame me lol) dynamically create a unique variable for each list that my for loop will create so that I can send a new object to my class.
I think I need to create a new list of student ID's and use that to create variables?
The file format looks like csv. Try this code:
import csv
students = []
with open('records.txt', 'r') as records:
reader = csv.reader(records)
for row in reader:
student = Student(
student_id = row[0],
student_name = row[1],
student_marks = row[2]
)
students.append(student)
try this
students=[]
with open('records.txt', 'r') as records:
for line in records:
#no need to replace all commas with spaces
id,name,mark = line.split(",")
#add student to student list
students.append(Student(id,name,mark))

Creating objects and adding them to a list by Reading CSV input in python

This is currently my code for reading through a CSV file, Creating a person object, and adding each person to a list. One line Example input: John,Langley,1,2,2,3,5
When i print(per) each time after creating a person object. My output is correct, but as soon as i add that person to the list i made, the numeric values AKA 'traits' for that person are all the same as the last persons traits in the CSV file.
For Example:
John,Langley,1,2,2,3,5 --(add to list)-->John,Langley,1,1,1,1,1
Isabel,Smith,3,2,4,4,0 --(add to list)-->Isabel,Smith,1,1,1,1,1
John,Doe,1,1,1,1,1 --(add to list)-->John,Doe,1,1,1,1,1
This is impacting me with continuing because i need the person objects' traits to be valid in order to perform analysis on them in the next couple methods. PLEASE IGNORE MY PRINT STATEMENTS. THEY WERE FOR MY DEBUGGING PURPOSES
def read_file(filename):
file = open(filename, "r", encoding='utf-8-sig')
Traits_dict = {}
pl = []
next(file)
for line in file:
line = line.rstrip('\n')
line = line.split(',')
first = str(line[0].strip())
last = str(line[1].strip())
w = line[2].strip()
hobby = line[3].strip()
social = line[4].strip()
eat = line[5].strip()
sleep = line[6].strip()
Traits_dict["Work"] = w
Traits_dict["Hobbies"] = hobby
Traits_dict["Socialize"] = social
Traits_dict["Eat"] = eat
Traits_dict["Sleep"] = sleep
per = Person(first, last, Traits_dict)
print(per)
pl.append(per)
print(pl[0])
print(pl[1])
print(pl[2])
print(pl[3])
print(pl[4])
return pl
All the Traits_dict = {} are the same to all object since you initiating the dict before the loop so it's giving each Person object the same dict reference in it.
You can put the Traits_dict = {} inside the loop that it will create each Person a new dict
for line in file:
Traits_dict = {}

Writing out results with function in.txt document when there's min and max?

I need a program that would read information from a .txt file, which contains a person's name and his/her age. The trick is that there can be any amount of names and ages, but they also can repeat but count as one person.
The program needs to write the youngest, then the oldest person in a new .txt document.
The .txt it needs to read from looks like this:
Sarah 18
Joshua 17
Michael 38
Tom 18
Sarah 18
Michael 38
Then after the program is done with the names it should write into a new .txt file like this:
Joshua 17
Michael 38
So far, I have this:
def parse_info():
info = open("info.txt", "r")
max_age = 0
max_name = ''
min_age = float('inf')
min_name = ''
for line in info:
m_list = line.split(" ")
if int(m_list[1]) > max_age:
max_age = int(m_list[1])
max_name = m_list[0]
elif int(m_list[1]) < min_age:
min_age = int(m_list[1])
min_name = m_list[0]
info.close()
I'm not sure how to make the program create a new .txt and write the youngest and oldest. Any help?
You can use the write() method of file objects to write strings into the file
with open("new.txt", "w") as output_file:
output_file.write( "{0} {1}\n".format(max_name, max_age) )
output_file.write( "{0} {1}".format(min_name, min_age) )
def parse_info():
info = open("info.txt", "r")
max_age = 0
max_name = ''
min_age = float('inf')
min_name = ''
for line in info:
m_list = line.split(" ")
if int(m_list[1]) > max_age:
max_age = int(m_list[1])
max_name = m_list[0]
elif int(m_list[1]) < min_age:
min_age = int(m_list[1])
min_name = m_list[0]
info.close()
return ((min_name,min_age),(max_name,max_age))
#end of function
nameAge=parse_info()
f = open("output.txt","w")
f.write(nameAge[0][0]+" "+str(nameAge[0][1])+"\n")
f.write(nameAge[1][0]+" "+str(nameAge[1][1]))
that should work
You can very easily let Python do all the hard work by combining the properties of a set with the properties of how a list of tuples is sorted.
def parse_info():
persons = set()
for line in open('info.txt'):
name, age = line.split()
persons.add((int(age), name)) # Note that age comes first
# At this point, we have removed all duplicates, now we need
# to extract the minimum and maximum ages; we can simply do
# this by converting the set to a list and then sort the list.
# If a list entry is a tuple, the default behaviour is that it
# sorts by the first entry in the tuple.
persons = sorted(list(persons))
# Now write the data to a new file
fd = open('new_info.txt', 'w')
age, name = persons[0]
fd.write('Youngest: %s %d\n' % (name, age))
age, name = persons[-1]
fd.write('Oldest: %s %d\n' % (name, age))
parse_info()

How do I append to a new object?

I have this function in python 3 that works almost as I want it to work:
def read_people_from_file(filename):
"""Function that reads a file and adds them as persons"""
print("reading file")
try:
with open(filename, 'rU') as f:
contents = f.readlines()
except IOError:
print("Error: Can not find file or read data")
sys.exit(1)
#Remove blank lines
new_contents = []
for line in contents:
if not line.strip():
continue
else:
new_contents.append(line)
#Remove instructions from file
del new_contents[0:3]
#Create persons (--> Here is my problem/question! <--)
person = 1*[None]
person[0] = Person()
person[0] = Person("Abraham", "m", 34, 1, 140, 0.9, 90, 0.9, 0.9)
for line in new_contents:
words = line.split()
person.append(Person(words[0], words[1], words[2], words[3], words[4], words[5], words[6], words[7], words[8]))
return person
In the last chunk of code, below "#Create persons", is a thing that I have not figured out how to do.
How do I create the empty list of persons and then add persons from the file?
If I remove the hard coded person named "Abraham", my code does not work.
The file is a text file with one person per row with the attributes coming after the name.
Part of the Person class looks like this:
class Person:
def __init__(self, name=None, gender=None, age=int(100 or 0), beauty=int(0), intelligence=int(0), humor=int(0), wealth=int(0), sexiness=int(0), education=int(0)):
self.name = name
self.gender = gender
self.age = age
self.beauty = beauty
self.intelligence = intelligence
self.humor = humor
self.wealth = wealth
self.sexiness = sexiness
self.education = education
I hope that the above code is self explanatory.
I suspect that there is some more pythonian way of doing what I want.
Any help is appreciated.
You can do
persons = []
...
for line in new_contents:
words = line.split()
persons.append(Person(...))
There's always:
persons = [Person(*line.split()) for line in new_contents]
This is probably the simplest way to do what you want:
def readfile():
data = open("file path to read from","r") #opens file in read mode
people = []
for line in data: #goes through each line
people.append(Person(*line.split())) #creates adds "Person" class to a list. The *line.split() breaks the line into a list of words and passes the elements of the list to the __init__ function of the class as different arguments.
return people

Categories

Resources