Naming auto generated objects, python - python

Text in italic can be skipped.
First of all: Forgive me if what I'm asking for is basic knowledge, easy to find answers too, or anything similar that may make my post annoying to anyone. I'm new to programming, and just started it to have an excuse not to read for exams.
I'm trying to make a program that can kind of mimic evolution from a tribe of humans to..well, a more advanced tribe of humans. My goal is to some time in the future make a very simple Civilization-like game that focuses on people rather than buildings and units. Starting from scratch, knowing pretty much nothing about programming at the moment, i know this is a task I will probably never complete. Hopefully I'll learn something on the way though.
Because my knowledge is so limited, my questions will be clumsy and badly formulated. I'm sorry, thanks for reading.
The current problem:
I've made a class that makes objects that are supposed to represent people.
The class looks like this at the moment:
class Settler:
settlerCount = 0
iqlistfemale = []
iqlistmale = []
maleCount = 0
femaleCount = 0
surnameMale = []
surnameFemale = []
def __init__(self, sex):
if sex=="m" or sex=="f" or sex=="M" or sex=="F":
self.name = choice(surnames)
Settler.settlerCount += 1
self.iq=round(random.normalvariate(100,10))
if sex=="m" or sex=="M":
self.sex = "Male"
Settler.iqlistmale=Settler.iqlistmale+[self.iq]
Settler.surnameMale += [self.name]
Settler.maleCount += 1
else:
self.sex = "Female"
Settler.iqlistfemale=Settler.iqlistfemale+[self.iq]
Settler.surnameFemale += [self.name]
Settler.femaleCount += 1
It will contain way more attributes later, this is just a beginning.
I've also made a loop that will ask you for an amount of males to create, and then an amount of females to create.
The loop-thing looks like this:
x=int(input("Number of male Settlers to generate? (1-20) "))
if x >0 and x <21:
tellergenerator=0
while tellergenerator<x:
Settler("M")
tellergenerator=tellergenerator+1
else:
print("Wrong input!")
x=int(input("Number of female Settlers to generate? (1-20) "))
if x >0 and x <21:
tellergenerator=0
while tellergenerator<x:
Settler("F")
tellergenerator=tellergenerator+1
else:
print("Wrong input!")
Also, I've made a def thing that will allow you to call for information on the attributes of an object:
def displaySettler(self):
print("Name:", self.name, "Sex:", self.sex, "IQ:", self.iq)
Now, for the questions:
Main question: My loop-thing works fine, meaning it creates the number of objects of the right sex that I want to create. My problem is that it creates objects without names, as far as I know. This means I can't do the displaySettler() call, because it requires me to do nameofobject.displaySettler(). How can I, using some sort of loop function to create a bunch of objects, make those objects with names.
I've found a way to combine a number to a string, which might allow me to put into the loop a system that creates object names like settler1, settler2, settler3, but the way I do that is to do something like
x=settler
y=(some counter)
z=x+str(y)
Is that something I can use? The only way I know to create my objects with name is by writing something like
settler1=Settler("F")
or
w=Settler("F")
is it possible to use the contents of variable z to name something?
I'd also like to ask the following: As you might see from my class, I'm doing a bunch of lists. I'm thinking I have to make a list for every attribute for every sex, containing the particular attributes of all objects. I want those lists to be able to calculate the populations average value of each attribute, and things like that.
Is it possible to get those values directly from the objects, and go through all the objects directly and calculate the average from that?
Or to put it another way: If I have 200 objects, is there some way to get the IQs of all the objects added together?
Thanks for reading (if anyone got this far). All constructive feedback will be much appreciated.

You need to have your person generator record the generated people in a data structure, such as a list or dictionary, then access those people from that created structure. In place of your while loop, try:
people = []
for i in range(x):
people.append(Settler('M')) # or 'F', for the other loop
Then you can use:
people[n].displaySettler() # where n is any integer from 0 to x-1

Two things:
1) it's better to have two distinct classes, Male and Female, both of them extend the base class Settler. Thus you avoid the most of if sex = M then this else that stuff
Example:
class Settler:
def __init__(self, name):
self.name = name
self.iq = round(random.normalvariate(100,10))
class Male(Settler):
def __str__(self):
return '{0.name}, male, iq {0.iq}'.format(self)
class Female(Settler):
def __str__(self):
return '{0.name}, female, iq {0.iq}'.format(self)
Note how both classes use __str__ to "represent" themselves in a string form.
2) keep all stuff concerning lists of objects outside of objects definitions. Good objects don't know what's happening outside them. For example, this is how to generate a list of people:
def generate(klass, how_many):
surnames = ['Doe', 'Smith', 'Mueller', 'Polly-Parrot']
return [klass(random.choice(surnames)) for _ in range(how_many)]
people = generate(Male, 10) + generate(Female, 20)
[stuff for _ in range(N)] basically means "do stuff N times".
Finally, let's put it all together and print a list of people:
for person in people:
print(person)
The output will be something like:
Doe, male, iq 114.0
Doe, male, iq 110.0
Polly-Parrot, male, iq 89.0
Smith, male, iq 96.0
Polly-Parrot, male, iq 83.0
Mueller, female, iq 118.0
Mueller, female, iq 90.0
Smith, female, iq 90.0
Smith, female, iq 103.0
Mueller, female, iq 89.0
Smith, female, iq 87.0
Let us know if you have more questions.

in response to your second question, and let's say that you had a list of Settlers called people (this is a list comprehension)...
iqs = [person.iq for person in people]
total_iq = sum(iqs)

Edit: Sr2222 beat me to it. I think we are using the same idea.
Not sure if this is the best way, but:
You are able to store objects in a dict, using names generated from a loop.
As an example:
group_of_vars = {}
for name in range(5):
entry = 'object_'+str(name)
group_of_vars[name] = entry
print group_of_vars
print group_of_vars
{0: 'object_0', 1: 'object_1', 2: 'object_2', 3: 'object_3', 4: 'object_4
Therefore
>>> print group_of_vars[1]
object_1
So by using this knowledge, you could make a list of variable names (auto-generated or manually) and keep it in a list. Then reference the name of the list as your range in the for-loop, and refer to each variable in that list.
As for getting the sum of all IQ's of the objects added together, you could do (following my earlier example, assume that the entries in the dict are objects with iq property values)
sum = 0
for name in group_of_vars:
sum += group_of_vars[name].iq
>>> print sum
This should return the sum of the iq property of all objects in the dict group_of_vars.

Related

What would be the most efficient or useful way to store attendance data?

I want to move my schools attendance records away from excel sheets and into python, but I'm not sure what the best way to store that data would be.
Method 1
Create a dictionary with student names as keys, and the dates they attended as items in a list. Or perhaps a list of the days they were absent would be more efficient.
attendance = {}
attendance["student_1"] = [2018-08-10, 2018-08-15, 2018-08-20]
Method 2
Create a dictionary of dates and append a list of students who were present on that day:
attendance = {}
attendance["2018-08-10"] = [student_1, student_2, student_3]
Method 3
Created nested dictionaries. Students names as the outer keys. All dates as inner keys with a boolean as a value.
attendance = {}
attendance["student_1"]= {}
attendance["student_1"]["1018-08-10"] = 'True'
All of these would probably work, but there must be a better way of storing this data. Can anyone help?
I should add that I want to be able to access the student's attendance record from name and retrieve all the student names that were present given a particular date.
It Completely depends on your use case. Each method has got its own advantage.
Method 1
attendance = {}
attendance["student_1"] = [2018-08-10, 2018-08-15, 2018-08-20]
total_days_present_student_1 = len(attendance["student_1"])
You have the advantage of getting easily the no. of days a student was present
Method 2
attendance = {}
attendance["2018-08-10"] = [student_1, student_2, student_3]
total_student_present_on_2018_08_10 = len(attendance["2018-08-10"])
You have the advantage of getting the total no. of students present on a particular day
Method 3
attendance = {}
attendance["student_1"]= {}
attendance["student_1"]["1018-08-10"] = 'True'
Not really any special advantage which the other 2 methods are providing
I'm not sure whether you've delved into OOP (object-oriented programming), but this approach may be useful if you need to store more than just attendance in the future. See my 'basic' example:
Setup objects
students = []
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
self.attendance = {}
def add_attendance(date, students, values):
for student, val in zip(students, values):
student.attendance[date] = val
Setup students
This part could be done by reading from a text file with student data, but I've simplified here for brevity.
students = [
Student('Bob', 15),
Student('Sam', 14)
]
Add a day and record attendance
Again, I've hard-coded the dates here, but this would obviously come from an external source; the datetime module may prove useful here.
current_date = '27-08-2018'
attendance_values = [
True, # for Student(Bob)
False # for Student(Sam)
]
add_attendance(current_date,
students,
attendance_values)
Now, I'll add a 2nd day (Hard-coded for demonstration):
current_date = '28-08-2018'
attendance_values = [True, True]
add_attendance(current_date, students, attendance_values)
Display information
I can easily display all information:
>>> print('\n'.join([str(s.attendance)
... for s in students]))
{'27-08-2018': True, '28-08-2018': True}
{'27-08-2018': False, '28-08-2018': True}
Or, in a more 'friendly' way, and with each student name:
>>> print('data for 27-08-2018:')
>>> for student in students:
... print('{:>10}: {}'.format(student.name,
... student.attendance['27-08-2018']))
data for 27-08-2018:
Bob: True
Sam: False
Storing externally
Currently, all data will be lost on the program's termination, so a possible text file structure could be the following.
Students:
Bob 15
Sam 14 # more data fields in columns here
Attendance:
27-08-2018
Bob True # or anything else to signify they were present
Sam False
28-08-2018
Bob True
Sam True
Now you could read each file line by line, splitting by whitespace for the 'students' file, but for the 'attendance' file, things will most certainly be more difficult. This all depends on what data you include in your attendance file: it could just be a date with True/False values or a fully formatted record.
I want to move my schools attendance records away from excel sheets and into python, but I'm not sure what the best way to store that data would be.
Actually, none of the example you posted are about storing data (persist them between program executions). Updates to your attendance dict during the program's execution will be lost when the process finishes, and I seriously doubt you want your program users to edit the python code to add or change data.
To make a long story short, this kind of programs want a SQL database - which not only takes care of persisting your data but also makes querying much easier.

Filter search function in Tkinter python for lists

So this is what my GUI looks like:
GUI
,and where i need help with is if i type a subject code it must show all the students with the that particular subject. Here is my code for the search function and add function:
def add_student():
Sname = Student_name.get()
Ssurnname = Student_surname.get()
Sdetail = Student_detail.get()
Snumber = Student_number.get()
i = Students(Sname,Ssurnname,Sdetail,Snumber)
Sinfo.append(i)
iName = Student_subject.get()
iCode = Student_code.get()
iMark1 = Student_Mark1.get()
iMark2 = Student_Mark2.get()
iMark3 = Student_Mark3.get()
iProject = Student_project.get()
j = Subjects(iName,iCode,iMark1,iMark2,iMark3,iProject)
SSubject.append(j)
kCourse = Degree_course.get()
kCode = Degree_code.get()
kYear = Degree_year.get()
v = Degrees(kCourse,kCode,kYear)
SDegree.append(v)
popup_add()
student_list.append(Sinfo)
student_list.append(SSubject)
student_list.append(SDegree)
def filter_data():
top3 = Toplevel()
top3.geometry('300x300')
top3.title("Search")
Searchlabel = Label(top3, text = "Please enter the Subject code: ")
Searchlabel.grid(column=1, row=1, sticky = (W,E))
searchValue = StringVar()
top3.searchBox = ttk.Entry(top3, textvariable=searchValue).grid(column=1, row=2, sticky = (W,E))
def searchdata(*args):
print("*")
resultList.delete(0,END)
searchkey = searchValue.get()
for student in student_list:
if searchkey == student[0]:
resultList.insert(END,str(student))
elif searchkey == student[1]:
resultList.insert(END,str(student))
top3.button_1 = Button(top3, text = "Search", command = searchdata)
top3.button_1.grid(column=3, row=2, sticky = (W,E))
Observations
In the code you posted, it appears that student_list is a list with exactly three elements: a list of Students objects, a list of Subjects objects, and a list of Degrees objects. I make that observation based on these lines of code:
...
Sinfo.append(i)
...
SSubject.append(j)
...
SDegree.append(v)
...
student_list.append(Sinfo)
student_list.append(SSubject)
student_list.append(SDegree)
I have no way of knowing if that's your intent, or if that's the first bug. I also have no way of knowing if it will always have exactly three or more than three (but always a multiple of three).
Assuming that it's intentional that student_list will always have exactly three elements, this loop is incorrect:
for student in student_list:
if searchkey == student[0]:
resultList.insert(END,str(student))
The first time through the loop, student will itself be a list of Students. The second time through the loop, student will be a list of Subjects), and the third time through it will be a list of Degrees.
Suggestions
Assuming that your data structures are intentional and that your ultimate goal is to be able to generate a list of students based on a given subject code, you will need to iterate over the list of subjects, not students.
Given the current code structure, you would need to do something like this (using a temporary variable subjects for clarity):
subjects = student_list[1]
for subject in subjects:
...
However, given that the students are in one list but the subjects are in another, you need to keep track of the index in the list of the subjects so that you can use the same index to reference the related student.
Note: This would be much easier if the subjects were an attribute of the student, so you might want to consider making the subjects and degrees attributes of a student.
We can keep track of the index within the list of subjects by using python's enumerate function:
for index, subject in enumerate(subjects):
...
Within the loop, you need to compare what the user entered with the subject code, and if you find it, you need to insert the corresponding student in the window.
Without knowing for certain, I'm going to assume that the Subjects class provides the subject code as the attribute code. I have no way of knowing if that's a correct assumption.
students = student_list[0]
subjects = student_list[1]
for index, subject in enumerate(subjects):
if searchkey == subject.code:
this_student = students[index]
resultList.insert(END, str(thisstudent))
Solving the problem through better data structures
The real solution to your problem might be to rethink some of your design choices. Instead of keeping student info, student subjects, and student grades in three separate lists, you might want to consider creating a Student class that has the info, subjects and lists as attributes. With that, all of the data for a student is in one place.
For example:
class Student(object):
def __init__(self, info, subjects, grades):
self.info = info
self.subjects = subjects
self.grades = grades
You would then create student_list like this:
student_list.append(Student(Sinfo, SSubject, SDegree))
With that you can loop over these students in a slightly more easy and understandable way:
for student in student_list:
for subject in student.subjects:
if subject.code == searchkey:
resultList.insert(END, str(student.info))
You can make this even easier by creating a method that can do the test for you:
class Student(object):
def has_subject(code):
for subject in self.subjects:
if subject.code == code:
return True
return False
Then, your loop becomes even clearer:
for student in student_list:
if student.has_code(searchkey):
resultList.insert(END, str(student.info))
Final thoughts
My answer could be wrong, because your question lacks a considerable amount of information. This is why we ask for a Minimal, Complete, and Verifiable Example that actually runs. Without it, we have to make many guesses and assumptions about your code. If the assumptions are bad, I will have wasted half an hour addressing the wrong problem, and you will have wasted time reading an answer that isn't relevant.
Finally, it would be easier for you to get help if you were to write code that conforms to PEP8 naming standards. Your code is difficult to read because of your unconventional use of uppercase characters. People tend to not want to provide answers to code that is difficult to read.

Python: Creating an unique variable to store information

I am doing a program that simulates population growth, but I am not competent enough to understand how to assign a variable to a newly generated person.
Here's my (very much incomplete) code so far:
from random import seed
from random import randint
seed()
m = "male"
f = "female"
class Person:
def __init__(self, gender, age):
if gender == 0:
self.gender = m
else:
self.gender = f
self.age = age
def person_Birth():
x = Person(randint(0,1), 0)
return x
new_Person = person_Birth() #here's the problem
Every time i want to "cause birth" to a new human, how can i store his/her information separately i.e. automatically assign a new variable to store his/her information without explicitly stating a new variable?
I'm sorry if this is confusing to you, I am not sure of the correct terms.
You need to store the references to the people in a container structure like a list or a dictionary:
people = []
for _ in range(20):
people.append(person_Birth())
Now the people list would contain 20 instances of Person, which you can either iterate over, or access each one individually with people[0] to people[19].

Create random, unique variable names for objects

I'm playing around with Python and any programming language for the first time, so please bear with me. I started an online class two weeks ago, but try to develop a small game at the side to learn faster (and have fun). It's a text adventure, but is shall have random encounters and fights with enemies that have random equipment that the players can then loot.
This is my problem: If I create random objects/weapons for my random encounter, I need to make sure that the object has a unique name. The way the level is designed there could in theory be an infinite number of objects (it can be open ended, with encounters just popping up).
This is my approach so far
class Item_NPCs: #create objects for NPCs
def__init__(self, item_type, item_number):
# e.g. item_type 1 = weapons, item_type2 = potions, etc.
if item_type == 1 and item number == 1:
self.property1 = 5
self.property2 = 4
if item_type == 1 and item_number ==2:
# etc. :)
def prepare_encounter():
inventory_NPC = [] # empty list for stuff the NPC carries around
XXX = Class_Item(item_type, item_number) # I might randomize the arguments.
What is important is that I want "XXX" to be unique and random, so that no object exists more than once and can later be put into the player's inventory.
How to do that?
Joe
Why do you need it to be random ? You could simply use a list, and append every new object to the list, with its index being its unique identifier :
items = []
items.append( Class_Item(item_type, item_number) )
But if you really need random identifier, maybe you can use a dictionary :
items = dict()
items[random_id] = Class_Item(item_type, item_number)
This requires random_id to be hashable (but it should be if it is a number or a string).
I don't know why others haven't thought of this:
yourvariableName = randint(0,1000)
exec("var_%s = 'value'" % yourVariableName)
I just thought of it myself. I hope it helps you.
A downside is you can't just do this:
print(var_yourVariableName)
you can only do this:
exec("print(var_%s)" % yourVariableName)
But you can probably circumvent this one way or another. Leave a comment if you manage to figure it out.
One more downside — if used in certain ways, it could be very insecure (as we are using exec), so make sure to cover any holes!

Python; List index out of range [address book task]

I'm currently studying Computer Science at GCSE level, and am nearing my first controlled assessment. Last week we moved onto learning about lists, but for the purpose of this weeks assignment, we need to create an improved version of our address book task using a 2D array. The purpose of the task is to allow the user to enter as many people as they require into an address book, and ask them for four pieces of information. This information is to be then printed onto the screen underneath.
Be that as it may, I'm encountering an error when entering more than one person into the address book, with the error list index out of range. I've read some posts on here already about the aforementioned error, but still don't seem to quite understand it fully. Any aid would be highly appreciated.
Here is my code thus far:
addressbook = ([])
number = int(input("How many people would you like in your address book:"))
for loop in range (0,number,1):
addressbook.append([(str(input("\nPlease enter your full name:")))])
addressbook.append([(str(input("Please enter your home address:")))])
addressbook.append([(str(input("Please enter your hometown:")))])
addressbook.append([(str(input("Please enter your mobile number:")))])
print("\nName:",addressbook[0][loop],"\nHomeaddress:",addressbook[1][loop],"\nHometown:",addressbook[2][loop],"\nMobile number:",addressbook[3][loop])
With the following error appearing:
Traceback (most recent call last):
File "C:\Users\Owner\Documents\Computer Science\Python\Address%20book.py", line 23, in <module>
print("\nName:",addressbook[0][loop],"\nHomeaddress:",addressbook[1][loop],"\nHometown:",addressbook[2][loop],"\nMobile number:",addressbook[3][loop])
IndexError: list index out of range
Rather than think of addressbook as a two-dimensional array of information about people, think of each dimension separately. An addressbook is a one-dimensional array of persons. Each person is, in turn, a one-dimensional array of information.
Bringing that thinking to our code can make the purpose much clearer:
# An address boook is an arary of persons
addressbook = []
number = int(input("How many people would you like in your address book:"))
# Create several persons, adding each to addressbook as we go:
for _ in range(number):
# Create one person:
person = []
person.append(str(input("\nPlease enter your full name:")))
person.append(str(input("Please enter your home address:")))
person.append(str(input("Please enter your hometown:")))
person.append(str(input("Please enter your mobile number:")))
# Add one person to addressbook
addressbook.append(person)
# Now addressbook has several persons
# Display addressbook, thinking of it as two-dim array
for loop in range(number):
print("\nName:",addressbook[loop][0],"\nHomeaddress:",addressbook[loop][1],"\nHometown:",addressbook[loop][2],"\nMobile number:",addressbook[loop][3])
# Display addressbook, thinking of it as array of persons:
for person in addressbook:
print("\nName:",person[0],"\nHomeaddress:",person[1],"\nHometown:",person[2],"\nMobile number:",person[3])
Other notes:
The statement addressbook = ([]) is identical to addressbook = []. Parentheses in that context do absolutely nothing.
Multi-dimensional arrays list the row number first, the column second. That is to say, the first number gets you to a row, and the 2nd number gets you to an element of that row. More simply, say addressbook[loop][0], not addressbook[0][loop].
The expression range(0, number,1) is identical to range(number), and the latter is easier to read.
In Python, if you need to assign a value but don't care about it further, use _, like so: for _ in range(number):.
The expression str(input(...)) is identical to the expression input(...), since input returns an object of type str. I left those alone because I suppose that verbose style is required by your instructor.
When the time comes, learn about breaking long expressions into multiple lines. Many people find that a line longer than about 80 characters is difficult to read.
You prompt the user "Please enter your full name" (emphasis added) each time. Presumably their name hasn't changed since the previous iteration of the loop. You are actually asking for some third party's full name. Try "Please enter their full name" or "Please enter this person's full name" or some such.
Finally, realize that computer programs will be read more often than they are written. This is true for professionally-maintained programs with hundreds of contributing programmers and also of one-off programs written by you for your own benefit. Use any means necessary to communicate effectively with the reader(s) of your program--comments, clear variable names, whitespace, whatever it takes.
First, Rob's explanation above is perfect for your assignment.
Now, I wanted to show you a few techniques, you can use, to make your life easier, without entering in OOP concepts and keeping the code as simple as possible, without error catching or whatsoever.
from collections import namedtuple
Person = namedtuple(
'Person',
('full_name', 'home_address', 'home_town', 'mobile_number')
)
person_print_template = '''
Full Name: {full_name}
Home Address: {home_address}
Home Town: {home_town}
Mobile Number: {mobile_number}'''
persons = []
number = int(input('How many people would you like in your address book: '))
for iteration in range(number):
full_name = input('\nFull name: ')
home_address = input('Home address: ')
home_town = input('Home town: ')
mobile_number = input('Mobile number: ')
person = Person(full_name, home_address, home_town, mobile_number)
persons.append(person)
for person in persons:
print(person_print_template.format(**person._asdict()))
collections.namedtuple is a way of defining really simple reusable objects and offers an _asdict() method which return a dictionary.
In python, putting ** in front of a dictionary allows you to unpack each of its dictionary keys and values which can be then passed, for example here, to a template, and str.format() will replace the "{key_name}" by its value.
Again this is a powerful way of formatting string output, especially when multi-line.=, either for the web or for command line output, like here.
Rob's answer, as Apero stated, is perfect. However as Apero addressed your format with functional programming, I'll address it in OOP (mostly because I love abstracting functional code! :D)
from collections import OrderedDict
# this is only necessary if you need your fields to always be in the
# same order when they're printed. Otherwise ignore and have Person
# inherit from dict
FIELDS = ["full name", "address", "hometown", "mobile number"]
class Person(OrderedDict): # see note above
def __init__(self, keys=None):
super().__init__() # this is magic that makes the OrderedDict work
if isinstance(keys, dict):
self.update(keys)
# this allows you to pass in a normal dict like you can for any
# other dict or ordered dict, and only prompt otherwise
else:
for key in keys:
self[key] = input("Please enter your %s: " % key)
def __str__(self):
"""The __str__ function describes how str(self) looks. I'm defining
it here to mimic the way Apero used his person_print_template string"""
output_strings = []
for key,value in self.items():
output_strings.append("{}: {}".format(key, value))
return "\n".join(output_strings)
# this is equivalently:
## return "\n".join(["{}: {}".format(key,value) for key,value in self.items()])
class AddressBook(list):
def __init__(self, size=None):
if size is None:
size = int(input("How many entries are in this address book? "))
for entry in range(size):
global FIELDS
self.append(Person(FIELDS))
def __str__(self):
return "\n\n".join([entry for entry in self])
# double spaced for readability
if __name__ == "__main__":
book = AddressBook()
print()
print(book)
# OUTPUT:
How many entries are in this address book? 2
Please enter your full name: Adam Smith
Please enter your address: 123 Some St.
Please enter your hometown: Eugene, OR
Please enter your mobile number: 555-867-5309
Please enter your full name: John Smith
Please enter your address: 987 Hello World, Ave.
Please enter your hometown: Camelot (tis a silly place)
Please enter your mobile number: 555-789-1234
full name: Adam Smith
address: 123 Some St.
hometown: Eugene, OR
mobile number: 555-867-5309
full name: John Smith
address: 987 Hello World, Ave.
hometown: Camelot (tis a silly place)
mobile number: 555-789-1234
You can certainly make changes in format to suit. I'd point you at the str.format method so you can do things like justify your strings beautifully
# # inside Person.__str__
for key,value in self.items():
global SCREENWIDTH # perhaps 50?
output_strings.append("{0}: {1:>{2}}".format(key,value, SCREENWIDTH - len(str(key)) - 1))
full name: Adam
address: blah
hometown: doohickey
mobile number: 1234
Possibly a flag on AddressBook.init that works as an alternate constructor given an existing list of Person objects.
class AddressBook(list):
def __init__(self, argument=None, _prompted=True):
if _prompted:
size = argument # just for clarity
self.from_prompt(size)
else:
lst = argument # just for clarity
self.from_list(lst)
def from_prompt(self, size):
# exactly as __init__ is above
def from_list(self, lst):
self.extend(lst)
Lots of fun stuff to be done with OOP. Personally I like them just because of Python's duck typing only becomes stronger when I can control both what kind of quack to listen to and what kind of quack to MAKE! :)
Use this instead
for loop in range (0,number,1):
addressbook.append([])
addressbook[-1].append([(str(input("\nPlease enter your full name:")))])
addressbook[-1].append([(str(input("Please enter your home address:")))])
addressbook[-1].append([(str(input("Please enter your hometown:")))])
addressbook[-1].append([(str(input("Please enter your mobile number:")))])
print("\nName:",addressbook[-1][0],"\nHomeaddress:",addressbook[-1][1],"\nHometown:",addressbook[-1][2],"\nMobile number:",addressbook[-1][3])
The problem with your code was you were using single dimension list. For every loop you are adding the items into addressbook so after 2 iterations of the loop it will look smthing like this
["name1","addr1","hmtown1","mob1","name2","addr2","hmtown2","mob2"]
So instead solution would be add an empty list for every iteration in loop and to that empty list we add the details so the structure would look like this
[["name1","addr1","hmtown1","mob1"],["name2","addr2","hmtown2","mob2"]]
In every iteration we access the last list by addressbook[-1] and then append the items to that last list, similarly accessing the items by using addressbook[-1][0].
Hope this helped you understand the problem.

Categories