First I'd like to mention that I am completely new to Python and I've found it a bit difficult to transition from C++. I apologize if my question comes off as elementary.
I have a class for 'songs' which I have initialized as following. It takes in data from a file that contains a song's ID, name, genre etc. all separated by ::.
def __init__(self):
self.song_names = dict()
self.song_genres = dict()
def load_songs(self, song_id):
f = open(song_id)
for line in f:
line = line.rstrip()
component = line.split("::")
sid = components[0]
same= components[1]
sgenre=components[2]
self.song_names[mid] = sname
self.song_genres[mid] = sgenre
f.close()
The program also takes in data from a file with 'users' information, separated as
UserID::Gender::Age::Occupation::Zip etc. and a file with 'ratings'.
I would I implement a function like def set_song(sid, list((title,genres)))
and something like delete_song(sid) ?
I'm going to have to wind up doing a ton more other functions, but if someone could help me with those two - at least to have a better idea of structure and syntax - handling the others should be easier.
Why not just inherit from dict and use its interface? That way you can use Python's standard mapping operations instead of rolling your own:
class Songs(dict):
def load(self, song_id):
with open(song_id, 'r') as f:
for line in f:
sid, name, genre = line.rstrip().split('::')[:3]
self[sid] = [name, genre]
mysongs = Songs()
mysongs.load('barnes_and_barnes__fish_heads')
mysongs['barnes_and_barnes__fish_heads'] = ['roly poly', 'strange'] # set
del mysongs['barnes_and_barnes__fish_heads'] # delete
Related
I am creating an interface with Pyqt. This interface generates a .txt file.
Basically in text_file, I generate the .txt file, where the title of the file is linked to radio_value and the content of the file in clickconector. The latter is where I have my problem. relleno is a list where is what is filled in the form, and form_label the labels of this. I need to join both lists into one, I tried from the most basic: a = zip (form_label, Relleno), but it gives an error: TypeError: can only join an iterable (I know it has to do with the join of a text file), and many others that basically gives the same error and I need to write that correctly (I know that the return of the code is wrong, it will only return the first tuple. I try to repeat that but with all the tuples)
I'll skip the part where I configure buttons to be more specific. Maybe It's a rookie mistake, but I've tried for hours and can't get what I want. Any constructive criticism is welcome
def clickconector (self):
relleno = [self.bitacora.text(), self.turno.text(), self.asesor.text(), self.item.text(), self.modelo.text(), self.identificacion.text(), self.rig.text(),self.horometro.text(),self.condicion.text(),self.orden.text(), self.observacion.text()]
form_label = ["bitacora", 'turno', 'asesor', 'item', 'modelo', 'identificacion', 'rig', 'horometro', 'condicion', 'orden', 'observacion']
for a,b in zip (form_label, relleno):
print (a,b)
def radio_value (self):
if self.pendiente.isChecked():
return 'Pendiente' , self.bitacora.text()
if self.terminado.isChecked():
return 'Terminado', self.bitacora.text()
def text_file(self):
filename = f"{' '.join(self.radio_value())}.txt"
with open(filename, "w") as f:
f.write(" ".join(self.clickconector()))
return f
Your error comes from the line
f.write(" ".join(self.clickconector()))
clickconector() doesn't return anything thus the error says only iterable~.
Try returning some text in iterable or just the text.
----- update -----
I'll change it like this
def clickconector (self):
relleno = [self.bitacora.text(), self.turno.text(), self.asesor.text(), self.item.text(), self.modelo.text(), self.identificacion.text(), self.rig.text(),self.horometro.text(),self.condicion.text(),self.orden.text(), self.observacion.text()]
form_label = ["bitacora", 'turno', 'asesor', 'item', 'modelo', 'identificacion', 'rig', 'horometro', 'condicion', 'orden', 'observacion']
return [str(label_text) for label_text in zip(form_label, relleno)] # just return list of tuples
def radio_value (self):
if self.pendiente.isChecked():
return 'Pendiente' , self.bitacora.text()
if self.terminado.isChecked():
return 'Terminado', self.bitacora.text()
def text_file(self):
filename = f"{' '.join(self.radio_value())}.txt"
with open(filename, "w") as f:
f.write(" ".join(self.clickconector()))
return f
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 = {}
I am making a program for my computer science assignment. I need to make a quiz for 3 classes in a primary school. Then the results have to be saved in a file. I've done the program till here but the next task asks me to let each student have 3 turns and give an average for each one.
here is the code I used to save the results into a text file:
def savetofile():
result = result ="\n "+ namestudent.get() + " "fscore.get()+"/4"
messagebox.showinfo("results", "your results been saved successfuly")
if int(year.get())==1:
f = open('results C1.txt', 'a')
f.write(result)
f.close()
if int(year.get())==2:
f = open('results C2.txt', 'a')
f.write(result)
f.close()
if int(year.get())==3:
f = open('results C3.txt', 'a')
f.write(result)
f.close()
how can I check if the new user taking the quiz has already done the quiz or not and how can I add the new results of that person in front of their name also how can I take the average of their 3 sets of score.
first of all, you output your results been saved successfully before writing to a file, which is not true, because the file writing can fail and thus not end up done successfully.
Then you do open and close your file in the following way:
f = open('results C1.txt', 'a')
f.write(result)
f.close()
which is wrong as well because if the write fails for any reason (like an exception reading the result variable), the file won't be closed properly, and the output may not get flushed to it.
You should instead do:
with open('results C1.txt', 'a') as f:
f.write(result)
which will take care of opening, flushing and closing the file correctly.
Then the following line is wrong:
result = result ="\n "+ namestudent.get() + " "fscore.get()+"/4"
as it misses a + between the spaces and the score result. You'd better write something like (with the \n at the end to avoid having an empty first line):
result = "{} {}/4\n".format(namestudent.get(), fscore.get())
how can I check if the new user taking the quiz has already done the quiz or not?
To do it you need to do the following algorithm:
# to open the file:
with open('results C1.txt', 'r') as results:
# read the file
for result in results:
# split the line
name, score = result.split(" ")
if name == namestudent.get():
# do something when the student exists
how can I add the new results of that person in front of their name also how can I take the average of their 3 sets of score?
Then my suggestion for this is to not work directly with the files, but instead open up a "cache" dictionary of all the scores:
def load_scores():
years_tuple_default = (None, None, None) # create a tuple with as many entries as there can be years
student_scores = dict()
with open('results C1.txt', 'r') as results:
# read the file
for result in results:
# split the line
name, score = result.split(" ")
student_scores.setdefault(name, years_tuple_default)[0] = score
with open('results C2.txt', 'r') as results:
# read the file
for result in results:
# split the line
name, score = result.split(" ")
student_scores.setdefault(name, years_tuple_default)[1] = score
with open('results C3.txt', 'r') as results:
# read the file
for result in results:
# split the line
name, score = result.split(" ")
student_scores.setdefault(name, years_tuple_default)[2] = score
return student_scores
Then, create a function save the cache into the files:
def save_scores(student_scores):
with open('results C1.txt', 'w') as results_y1:
with open('results C2.txt', 'w') as results_y2:
with open('results C3.txt', 'w') as results_y3:
for student, scores in student_scores:
results_y1.write("{} {}/4\n".format(student, scores[0]))
results_y2.write("{} {}/4\n".format(student, scores[1]))
results_y3.write("{} {}/4\n".format(student, scores[2]))
print("Results saved!")
And finally, work against that cache:
def update_scores(student_scores, namestudent, fscore, year):
if namestudent.get() not in student_scores.keys():
# add the student entry
student_scores.setdefault(namestudent.get(), (None, None, None))[int(year.get())-1] = fscore.get()
else:
# update the student year entry
student_scores[int(year.get())-1] = fscore.get()
which would end up with a code looking like that to put it all together:
student_scores = load_scores()
# do your stuff to get the namestudent/fscore/year data
update_scores(student_scores, namestudent, fscore, year)
# when all updates are done, you can alter the files
save_scores(student_scores)
To sum up:
split your algorithm into functions,
protect your file handling using the with statement
read the files once to create a "cache" to work against, and save the result at once when you're done
Bonus ideas
use a class
From there, to get further, you could create a class, and have all that as methods:
class StudentScores:
def __init__(self):
self._student_scores = dict()
def load_scores(self):
# TODO
def save_scores(self):
# TODO
def update_score(self):
# TODO
And then calculating the mean of the scores is simple stupid, it's just adding a method to the class which prototype would look like:
class StudentScores:
…
def get_mean_scores(self, student):
score_y1, score_y2, score_y3 = self._student_scores[student]
score = # calculate the average of the three score
return score
use a with statement
And if you want to shine, you could implement it as working with the with statement:
class StudentScores:
def __init__(self):
self._student_scores = dict()
def load_scores(self):
# TODO
def save_scores(self):
# TODO
def update_score(self):
# TODO
def __enter__(self):
self.load_scores()
return self
def __exit__(self, type, value, traceback):
self.save_scores()
And then your code would like that:
with StudentScores() as student_scores:
# do your stuff to get the namestudent/fscore/year data
update_scores(student_scores, namestudent, fscore, year)
To conclude, I'm showing you how I'd design something to do your assignment, whereas I'm not trying to do your assignment on your behalf. My goal here is to help you get ideas and learn something about software design and python. Some things may be above your current level (like how to create a with statement), but as you're learning, you'll be able to fully understand and apply everything I'm telling you here.
HTH
I am making a flashcard program in which I take a text file that contains several columns, such as english word, french equivalent, gender, type of word, etc. My idea was to create a loop that read each line of the text file, separating by tabs, and makes an instance of a user-defined Word object for each line.
In the following block code I import the text file, process it into a list, then attempt to create an instance of a previously defined object: Word. I would like the object to have the second item on the list for it's name so that it is easily searchable, but it's not letting me do this, please can somebody help me with the code:
file = (open('dictionary.txt', 'r')).readline()
import re
line_list = re.split(r'\t', file.rstrip('\n'))
line_list[1] = Word(line_list[0], line_list[1], line_list[2], line_list[3])
Create a dict of instances and use the second item of the lists as key. It's a bad idea to create dynamic variables.
import re
instance_dict = {}
with open('dictionary.txt') as f:
for line in f:
line_list = re.split(r'\t', line.rstrip('\n'))
instance_dict[line_list[1]] = Word(*line_list[:4])
Why the with statement?
It is good practice to use the with keyword when dealing with file
objects. This has the advantage that the file is properly closed after
its suite finishes, even if an exception is raised on the way.
You can also use the csv module:
import csv
instances = {}
with open('dictionary.txt', 'rb') as f:
reader = csv.reader(f, delimiter='\t')
instances = {line[1]: Word(*line) for line in reader}
Here's a cleaner solution using a namedtuple. You'll end up with a dict called "words" which you use to lookup each by name.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pprint
from collections import namedtuple
Word = namedtuple('Word', ['name', 'french', 'gender', 'type_'])
words = {}
with open('dictionary.txt', 'rU') as fin:
for word in (Word(*r.rstrip('\n').split('\t')) for r in fin):
words[word.name] = word
pprint.pprint(words)
Firstly, it's better to use with, as statements to get input from files, as the closing procedures are automatically taken care of. Secondly, to read ALL of the lines from a file, you must use readlines() rather than readline(). Try something like this :
with open('dictionary.txt','r') as file :
line_list = file.readlines()
splitLineList = []
for lines in line_list :
splitLineList.append(re.split(r'\t',lines.strip('\n'))
You may have an appropriate solution depending on few clarification on your requirements
"My idea was to create a loop that read each line of the text file,
separating by tabs, and"
If the text file is already pre-validated or reliable to ignore error-handling (e.g. not evenly separated by single tabs).
with open('dictionary.txt', 'r') as f:
[line.strip().split("\t")
for line in f.read().split("\n")
if line.strip()]
will get you the (comprehensive) list required to create Word object instances, without using re
"then attempt to create an instance of a previously defined object:
Word."
with open('dictionary.txt', 'r') as f:
[Word(line.strip().split("\t"))
for line in f.read().split("\n")
if line.strip()]
"I would like the object to have the second item on the list for it's
name so that it is easily searchable,"
Can you rewrite this with an example?
but it's not letting me do this,
line_list[1] = Word(line_list[0], line_list[1], line_list[2], line_list[3])
Sorry I am loosing you here, why are using line_list[1] to refer newly created Word instances where line_list[1] itself is an argument ?
With your clarification, I would have something like this
Reworked Code:
from pprint import pprint
My assumption on your Class definition:
class Word():
def __init__(self, **kwargs):
self.set_attrs(**kwargs)
def __call__(self):
return self.get_attr("swedish_word")
def set_attrs(self, **kwargs):
for k, v in kwargs.iteritems():
setattr(self, k, v)
def get_attr(self, attr):
return getattr(self, attr)
def get_attrs(self):
return ({attr.upper():getattr(self, attr) for attr in self.__dict__.keys()})
def print_attrs(self):
pprint(self.get_attrs())
if __name__ == '__main__':
# sample entries in dictionary.txt
# swedish_word english_word article word_type
# hund dog ett noun
# katt cat ett noun
# sova sleep ett verb
with open('dictionary.txt', 'r') as f:
header = f.readline().strip().split("\t")
instances = [Word(**dict(zip(header, line.strip().split("\t"))))
for line in f.read().split("\n")
if line.strip()]
# for line in f.read().split("\n"):
# data = dict(zip(header, line.strip().split("\t")))
# w = Word(**data)
You can get instance properties for a given swedish_word like this
def print_swedish_word_properties(swedish_word):
for instance in instances:
if instance() == swedish_word:
print "Properties for Swedish Word:", swedish_word
instance.print_attrs()
print_swedish_word_properties("hund")
to have output like this
Properties for Swedish Word: hund
{'ARTICLE': 'ett',
'ENGLISH_WORD': 'dog',
'SWEDISH_WORD': 'hund',
'WORD_TYPE': 'noun'}
or you can use any other class methods to search instances on various attributes
I am playing with cgi (uploading file form),
and I am receiving the files as storage object and I sotred it in (input) variable.
this is the simple iteration.
for file in input:
filepath = ....
filename, fileext = os.path.splitext(filepath)
file_real_name = ....
file_size = ....
file_type = ...
file_url = ....
file_short_name = ...
file_show_link = ....
# etc
it would be easy if it was only one file , but what If i have more than one ?
how can I have another value that holds all the iteration information in
like uploaded_files where I can access each uploaded file with all the information for the above iteration ?
I tried to read the docs but I cant wrap my head around some iteration concepts yet, sorry :)
You want to use a data structure to hold your data. Depending on the complexity, you may want to simply use a list of dictionaries:
files = []
for file in input:
files.append({
"path": get_path(file),
"name": get_name(file),
"size": get_size(file),
...
})
Or, if you find you need to perform lots of operations on your data, you might want to make your own class and make a list of objects:
class SomeFile:
def __init__(self, path, name, size, ...):
self.path = path
...
def do_something_with_file(self):
...
files = []
for file in input:
files.append(SomeFile(get_path(file), get_name(file), get_size(file), ...))
Note that here you are following a pattern of building up a list by iterating over an iterator. You can do this efficiently using a list comprehension, e.g:
[{"path": get_path(file), "name": get_name(file), ...} for file in input]
Also note that file and input are really bad variable names, as they will mask the builtins file() and input().
results = []
for i in range(5):
file_data = {}
file_data['a'] = i
file_data['b'] = i**2
results.append(file_data)
print results