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

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.

Related

Unexpected output (Python exercise)

My code is not printing the correct result for the test case
`2 6
1 alex
1 Alex
2 sam
1 alix
1 Alix
2 caM `
as it should result in "alex, sam", yet it results in "alex, Alex" (After reading the following instructions youll understand why). Was hoping I can get some insight as to what is wrong with my code.
Exercise: Dan’s recently announced that he’s teaching n top-secret courses next semester. Instead of enrolling in them through ACORN, students need to email Dan to express their interests. These courses are numbered from 1 to n in some arbitrary order. In particular, if a student named s is interested in taking a course c, they need to send an email to Dan containing the message c s. Note that if a student is interested in taking multiple courses, they need to send multiple emails, one per course. Upon receiving a message c s, Dan looks at the list of students already enrolled in course c. If there’s already a student on the list whose name is too similar to s, Dan assumes s is the same student and ignores the message. Otherwise, he enrolls s in the course. Dan considers two names too similar if and only if they have the same length and differ in at most one letter(note that “a” and “A” are considered the same letter). For example, “Josh” and “Josh” are too similar. “Sam” and “CaM” are too similar as well. However, neither “Max” and “Cat” nor “Ann” and “Anne” are too similar. Dan has a lot of students and teaches a lot of courses. Consequently, it would take him forever to process the messages sent by the students one-by-one manually. Instead, he’s asking you to help him out by writing a program that takes in the messages as the input and outputs, for every course, the list of the students enrolled in that course in the order of their enrolments.
****My code thus far: ****
`u = input()
u, w = u.split()
courses = int(u)
students = int(w)
names = []
classes = []
for i in range(students):
names_input = input()
selection = names_input.split()
course_num = selection[0]
student_name = selection[1]
if course_num not in classes:
classes.append(course_num)
names.append(student_name)
else:
if student_name not in names:
names.append(student_name)
print(classes)
print(names)
for i in range(0, len(classes)):
print(names[i])
`
You have to convert the name to lower or upper case.
Because to python alex and Alex are different things. You can convert a string to lowercase using the string method lower().
Like this :
student_name = selection[1].lower()

Bubble sort algorithm | 'str' object does not support item assignment - Python

The brief: I challenged myself to write a program, as asked in a textbook, to test my understanding and demonstrate proficiency in the 'bubble sort'. The problem asked to write a program that "allows the user to enter 20 names into a String array. Sort the array in ascending (alphabetical) order and display its contents." My initial code worked, however I wasn't satisfied and one unsuccessful attempted code change later, I am stumped for a viable solution.
The issue: I initially wrote the friendInput function with for a loop, that iterates 20 times (for listInput in range(20):), to allow for 20 individual inputs, respective to the 20 values for the user to input. Whilst this worked, I consider it quite tedious from a user perspective, especially with a range of 20, to have to keep typing, hitting return, then repeating for 20 values.
Original code:
def friendInput():
friendList = []
for listInput in range(20):
friendList.append(input("Please enter a friends name: "))
print("You added these to the list: "+' | '.join(friendList))
return friendList
Attempted code re-write:
def friendInput():
friendList = []
separator = ","
friendList = input("Please enter friend's names, separated with commas: ")
print("You added these to the list:",friendList.split(separator))
return friendList
I did some research and learnt a lot, including the .split() function and tried to implement this, unsuccessfully it appears.
Bubble sort algorithm:
def bubbleSort(friendList):
for friends in range (0, len(friendList) - 1):
for x in range (0, len(friendList) - 1 - friends):
if friendList[x] > friendList[x+1]:
friendList[x], friendList[x+1] = friendList[x+1], friendList[x]
return friendList
Error message:
Everything seemed logical in my head, until the debugger threw back a TypeError: 'str' object does not support item assignment. The TypeError: goes on to quote part of my bubbleSort function - friendList[x], friendList[x+1] = friendList[x+1], friendList[x]
Where I need help:
I suppose the error is really just saying that I'm trying to access and change a string, which is obviously disallowed, as it's not immutible. I am struggling to find a code change that would look clear, concise and not burden the user.
Can someone kindly offer suggestions, to remedy this error?
Re-read these lines:
friendList = input("Please enter friend's names, separated with commas: ")
print("You added these to the list:",friendList.split(separator))
return friendList
You are creating a string friendList = input... and then you are returning the string (return friendList). You intend to create a list and then return the list.
Try this instead:
friendList = input("Please enter friend's names, separated with commas: ")
friendList = friendList.split(separator)
print("You added these to the list:",friendList)
return friendList

Issues with lists? Error checking not working

I am relatively new to python, and I just started learning how to use classes. This is the first program I've made where I've tried to integrate them, but I'm coming up with a small issue I can't seem to fix, and I think it has to do with lists. The code is as follows:
(The topic is getting the user to choose what type of seat to purchase).
class SeatBooking:
def __init__(self, seat):
self.seat = seat
possible_types = []
possible_types.extend(["Low_Economy", "Standard_Economy", "High_Economy",
"Business", "First", "Residence"])
possible_types = " ".join(possible_types)
while True:
if self.seat not in possible_types:
print("Sorry, but this is not a valid answer. Please try again!")
self.seat = str(input("What type of ticket would you like? The possible types are: {} "
.format(possible_types)))
else:
print("You have chosen to book a {} ticket.".format(self.seat))
confirmation = str(input("Please confirm with 'Yes' or 'No': ")).lower()
if confirmation == "yes":
print("Excellent decision! Ready to continue")
print("=" * 170)
break
elif confirmation == "no":
self.seat = str(input("What type of ticket would you like? The possible types are: {} "
.format(possible_types)))
else:
print("That doesn't seem to be a valid answer.")
Here is the main file (to execute the different classes I'll make):
import type_seat
# Choose the seat to book
print("=" * 170)
print("Welcome to Etihad! This program can help you organize your flight, payments and usage of miles!")
possible_types = []
possible_types.extend(["Low_Economy", "Standard_Economy", "High_Economy",
"Business", "First", "Residence"])
possible_types = " ".join(possible_types)
seat_type = str(input("What type of ticket would you like? The possible types are: {}. "
.format(possible_types)))
type_seat.SeatBooking(seat_type)
The problem I have is that I seem to be able to enter certain letters and it doesn't count them as an error even though they're not one of the available seats. For example, when I enter the letters "h" or "s", my error checking part of the code doesn't respond to it, but when I enter the letter "b" or random words like "try" it does. It doesn't seem to be completely random though, and it seems to only happen with letters or parts of the first 3 'items' in the possible_types[] list. However, I haven't tested this fully. This is why I thought it had something to do with lists, so if anyone knows what's causing this, I'd really appreciate it if they could help me resolve this and perhaps help me from repeating this mistake in the future!
Note, for the lists I am using .join, but I also tried str().
You don't have a list, you are testing characters against one long string:
possible_types = " ".join(possible_types)
The letters h and s are in that string (in the words High_Economy and Business, respectively), but the sequence try doesn't appear anywhere in the string.
If you only wanted to allow whole words to match, you'd need to leave possbile_types a list, or ideally convert it to a set (as sets allow for fast membership testing). You can define the list, no need for list.extend() here:
possible_types = ["Low_Economy", "Standard_Economy", "High_Economy",
"Business", "First", "Residence"]
or make it a set by using {...}:
possible_types = {"Low_Economy", "Standard_Economy", "High_Economy",
"Business", "First", "Residence"}
Do not join this into a string, just test directly against the object:
if self.seat not in possible_types:
If you still need to show the values to a user in an error message, join the values then, or store the str.join() result in a different variable for that purpose.
Note that you shouldn't deal with user input validation in the class __init__ method. Leave user interaction to a separate piece of code, and create instances of your class after you validated. That way you can easily swap out user interfaces without having to adjust all your data objects too.
possible_types = " ".join(possible_types)
Above statement will create one string as "Low_Economy Standard_Economy High_Economy Business First Residence".
Now you are doing
if self.seat not in possible_types:
This will check for a particular character in the string present or not. In your case you are finding 'h' which is present and 'try' which isn't.
Your program will work if you remove this statement
possible_types = " ".join(possible_types)

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.

Naming auto generated objects, 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.

Categories