Dynamically generated Class instances - python

I want to store values that I plan to later use for sorting pdfs on my computer using PyPDF2.
I thought that if I created a class and stored identifying info for each type of file (such as a descriptor, a string that is unique to the file and can be found by PyPDF2 later such as an account number, and the path where the file should be moved to) that would work. Something like this:
class File_Sort(object):
def __init__(self, identifier, file_text, file_path):
self.identifier = identifier
self.file_text = file_text
self.file_path = file_path
so an example input from me would be:
filetype0001 = File_Sort("Phone Bill", "123456", "/Users/Me/PhoneBills/")
I would like to be able to have users generate new file types via a series of raw_input questions, but I can't figure how to generate the variable to create a new instance, so that I can get:
filetype000[automatically incrementing number] = File_Sort(UserResponse1, UserResponse3, UserResponse3).
Creating the "filetype000[automatically incrementing number]" text itself seems easy enough with:
file_number += 1
file_name = "filetype" + str(file_number).zfill(4)
but how do you turn the generated file_name string into a variable and populate it?

It sounds like you're wanting to dynamically create variables. That's almost always a foolish thing to do. Instead, you should be using a data structure like a list or dictionary, indexed by the parts of the variable name you wanted to generate dynamically.
So instead of creating a list named filetype000, start with a list named filetypes, and append an inner list, so you can do filetypes[0] to get at it. Or if string names make more sense for your specific application, let filetypes be a dictionary, and access the inner lists with something like filetypes['pdf'].
I'm being a little vague here because I don't really understand all of your pseudocode. It's not at all obvious what the purpose of the [automatically incrementing number] parts of your example are, so I'm more or less ignoring those bits. You probably just want to start with an empty list and append values to it, rather than somehow initializing it to a specific size and magically indexing it.

so fyi this is what I ended up using:
file_descriptor = []
file_string = []
file_location = []
filetype_new = len(file_descriptor)
input_descriptor = raw_input("What is the description of the new file type? ")
file_descriptor.append(input_descriptor)
input_filestring = raw_input("What is unique string to search for in this file type? ")
file_string.append(input_filestring)
input_filelocation = raw_input("where should we put this file type? ")
file_location.append(input_filelocation)
print("file%s: %s, \t%s, \t%s" % (str(filetype_new+1).zfill(4), file_descriptor[filetype_new], file_string[filetype_new], file_location[filetype_new]))
review = raw_input("\nWould you like to review the current files? y/n ").lower()
while review not in "yn":
review = raw_input("Sorry, I don't understand. Would you like to review your file types? y/n ").lower()
print("There are currently sort instructions for %s filetypes: " % (len(file_descriptor)))
file_increment = 0
while file_increment in range(0, len(file_descriptor)):
print("file%s: %s, \t%s, \t%s" % (
str(file_increment + 1).zfill(4), file_descriptor[file_increment], file_string[file_increment],
file_location[file_increment]))
file_increment += 1
thanks for your advice.

Related

Why python don't write anything into a dictionary?

I'm creating a program that saves his infos as encoded infos using a method that I created.
Basically when I start the program it creates two variables,
one is the alphabet (uppercase, lowercase, digits, ...)
the other is the exact same except that I use a random.shuffle() to randomize it.
That's the "key" to a "key" I give it a random number using random.randint(1000000000,9999999999) and this number I call it the name of the "key".
All the keys and theirs name are stored in a file.
In the program you have the opportunity to write something like a name, that name is going to be encrypted using the key that is generated when I start the program, then stored in a file along with the name of the key.
(Note that the keys always have a different name, the encrypted data may has been encrypted using many times the same key then stored in another file).
I read from the key file first
{NOTE: the keys are stored using a \n pattern, example
file.write(f'{key}\n{key_name}\n') }
using my method the length will always be divisible for 2 so I use a variable initialized before the for cycle and increase it along with the cycle, meanwhile I use that same variable to read from the list (the result of reading the key file) and assign a name to a key, example:
{4819572: 'varoabIfokdbKjs3918', 40101846: 'opqihduqv', 8291073: 'hqowirhwip', ...}
My keys are 354 chars long so those are a really small example.
Here is the code described above
sep = os.sep
Ot = platform.system()
file_name = os.path.basename(__file__)
path_to_file = __file__.replace(file_name, '')
with open(f'{path_to_file}database{sep}history.dll', 'r', encoding='utf-8') as file:
keys = file.readlines()
num = 0
archive = {}
for _ in range(int(len(keys)/2)):
key_name = str(keys[num+1]).replace('\n','')
key = str(keys[num]).replace('\n','')
archive[int(key_name)] = key
num =+ 2
num1 = 0
num2 = 0
After this I use the key_name to get the key which is used in a decrypt function along with the encrypted text.
The problem is that even if I have 16 keys in the dictionary there are only 2. I really don't know how to resolve this or why this is appending.
You have writen "num =+ 2", I think you wanted write "num += 2"

Parsing and arranging text in python

I'm having some trouble figuring out the best implementation
I have data in file in this format:
|serial #|machine_name|machine_owner|
If a machine_owner has multiple machines, I'd like the machines displayed in a comma separated list in the field. so that.
|1234|Fred Flinstone|mach1|
|5678|Barney Rubble|mach2|
|1313|Barney Rubble|mach3|
|3838|Barney Rubble|mach4|
|1212|Betty Rubble|mach5|
Looks like this:
|Fred Flinstone|mach1|
|Barney Rubble|mach2,mach3,mach4|
|Betty Rubble|mach5|
Any hints on how to approach this would be appreciated.
You can use dict as temporary container to group by name and then print it in desired format:
import re
s = """|1234|Fred Flinstone|mach1|
|5678|Barney Rubble|mach2|
|1313|Barney Rubble||mach3|
|3838|Barney Rubble||mach4|
|1212|Betty Rubble|mach5|"""
results = {}
for line in s.splitlines():
_, name, mach = re.split(r"\|+", line.strip("|"))
if name in results:
results[name].append(mach)
else:
results[name] = [mach]
for name, mach in results.items():
print(f"|{name}|{','.join(mach)}|")
You need to store all the machines names in a list. And every time you want to append a machine name, you run a function to make sure that the name is not already in the list, so that it will not put it again in the list.
After storing them in an array called data. Iterate over the names. And use this function:
data[i] .append( [ ] )
To add a list after each machine name stored in the i'th place.
Once your done, iterate over the names and find them in in the file, then append the owner.
All of this can be done in 2 steps.

Write list to CSV file in Python

I have created a quiz for students to take part to test their arithmetic skills. I wish to write the list of students and their scores to a csv file. I am struggling to write to file and although I have managed to, the excel file contains no data. It says "Score for [] : []". Very sorry for the inefficient code, but any help will do on how to solve this.
I created 2 empty lists and a variable.
Student = []
Score = []
QuizTaken = 0
This defines when to append the scores to the list.
def QuizTaken(): #the amount of quizzes taken by student
while QuizTaken <= 3:
userName, ClassName = Introduction() #used to input name and class using raw_input
score = Quiz()
Student.append(userName) #student's inputted name is appended to list
Score.append(score) #student's final score is appended to list
QuizTaken()
This code writes the list to file in the form of a string, however I think my problem lies here somewhere, however I can't locate it.
def WriteToFile():
userName, ClassName = Introduction()
score = Quiz()
print ""
if ClassName == "10x1":
print "Creating a text file for your teacher..."
fileWrite = open("10x1 Class Score.csv", "a+")
fileWrite.write("Score for ")
fileWrite.write(str(Student))
fileWrite.write(" : ")
fileWrite.write(str(Score))
fileWrite.write("\n")
fileWrite.close()
The code should write the names and scores appended into the empty list into a csv file, with the data available for me to view, but it shouldn't be overwritten.
There are a few problems with your code: you have QuizTaken as both function and variable name. You also don't increment your counter (QuizTaken) in the body of your loop. You can use pandas (http://pandas.pydata.org/) to store your data in dataframe and then use pandas.DataFrame.to_csv() to write it to a file.

Python 2 dicts merge

I am creating a dict to hold name and phone number, storing to local by pickle.
the issue now I am facing is: it seems like the merge is not working fine.
, any idea? thanks.
import pickle
def add(name,contact):
person= {};
person[name] = contact;
print('new added: ',person);
mycontactfile = 'contactlist.txt';
f = open(mycontactfile,'rb');
storedcontact = pickle.load(f);
f.close();
print('saved list:',storedcontact);
storedcontact.update(person); # add a new contact to the list
f = open(mycontactfile,'wb');
pickle.dump(storedcontact,f);
print('now full list is:' ,storedcontact);
If you have multiple contacts to go with a name, you'll need a dict of list. You would add contacts like this
if name in storedcontact:
storedcontact.append(contact)
else:
storedcontact[name] = contact
Better yet, stop using pickles and switch to sqlite
Aside:
you can also initialise person in one step like this (but you don't really need person anymore)
person = {name: contact}

Objects/classes/lists Python

I am confused about classes in python. I don't want anyone to write down raw code but suggest methods of doing it. Right now I have the following code...
def main():
lst = []
filename = 'yob' + input('Enter year: ') + '.txt'
for line in open(filename):
line = line.strip()
lst.append(line.split(',')
What this code does is have a input for a file based on a year. The program is placed in a folder with a bunch of text files that have different years to them. Then, I made a class...
class Names():
__slots__ = ('Name', 'Gender', 'Occurences')
This class just defines what objects I should make. The goal of the project is to build objects and create lists based off these objects. My main function returns a list containing several elements that look like the following:
[[jon, M, 190203], ...]
These elements have a name in lst[0], a gender M or F in [1] and a occurence in [3]. I'm trying to find the top 20 Male and Female candidates and print them out.
Goal-
There should be a function which creates a name entry, i.e. mkEntry. It should be
passed the appropriate information, build a new object, populate the fields, and return
it.
If all you want is a handy container class to hold your data in, I suggest using the namedtuple type factory from the collections module, which is designed for exactly this. You should probably also use the csv module to handle reading your file. Python comes with "batteries included", so learn to use the standard library!
from collections import namedtuple
import csv
Person = namedtuple('Person', ('name', 'gender', 'occurences')) # create our type
def main():
filename = 'yob' + input('Enter year: ') + '.txt'
with open(filename, newlines="") as f: # parameters differ a bit in Python 2
reader = csv.reader(f) # the reader handles splitting the lines for you
lst = [Person(*row) for row in reader]
Note: If you're using Python 2, the csv module needs you to open the file in binary mode (with a second argument of 'rb') rather than using the newlines parameter.
If your file had just the single person you used in your example output, you' get a list with one Person object:
>>> print(lst)
[Person(name='jon', gender='M', occurences=190203)]
You can access the various values either by index (like a list or tuple) or by attribute name (like a custom object):
>>> jon = lst[0]
>>> print(jon[0])
jon
>>> print(jon.gender)
M
In your class, add an __init__ method, like this:
def __init__(self, name, gender, occurrences):
self.Name = name
# etc.
Now you don't need a separate "make" method; just call the class itself as a constructor:
myname = Names(lst[0], etc.)
And that's all there is to it.
If you really want an mkEntry function anyway, it'll just be a one-liner: return Names(etc.)
I know you said not to write out the code but it's just easier to explain it this way. You don't need to use slots - they're for a specialised optimisation purpose (and if you don't know what it is, you don't need it).
class Person(object):
def __init__(self, name, gender, occurrences):
self.name = name
self.gender = gender
self.occurrences = occurrences
def main():
# read in the csv to create a list of Person objects
people = []
filename = 'yob' + input('Enter year: ') + '.txt'
for line in open(filename):
line = line.strip()
fields = line.split(',')
p = Person(fields[0], fields[1], int(fields[2]))
people.append(p)
# split into genders
p_m = [p for p in people if p.gender == 'M']
p_f = [p for p in people if p.gender == 'F']
# sort each by occurrences descending
p_m = sorted(p_m, key=lambda x: -x.occurrences)
p_f = sorted(p_f, key=lambda x: -x.occurrences)
# print out the first 20 of each
for p in p_m[:20]:
print p.name, p.gender, p.occurrences
for p in p_f[:20]:
print p.name, p.gender, p.occurrences
if __name__ == '__main__':
main()
I've used a couple of features here that might look a little scary, but they're easy enough once you get used to them (and you'll see them all over python code). List comprehensions give us an easy way of filtering our list of people into genders. lambda gives you an anonymous function. The [:20] syntax says, give me the first 20 elements of this list - refer to list slicing.
Your case is quite simple and you probably don't even really need the class / objects but it should give you an idea of how you use them. There's also a csv reading library in python that will help you out if the csvs are more complex (quoted fields etc).

Categories

Resources