So I was writing a program in Python, which would take all my university classes (from csv) and print info about them. I've wrote a simple class Subject to manage everything better. In my uni there are classes in even weeks, odd weeks, and every-week classes, and I have lectures, exercises and laboratories. So my Subject class is like this:
class Subject:
number = 0
name = ""
dummyData = []
even = {}
odd = {}
all = {}
type = ""
def __init__(self, name, number, type):
self.name = name
self.number = number
self.type = type
self.info = str(number) + " " + name + " " + type
Previously I had all days written in even, odd, and all dicts, like this:
even = {"mon":"",
"tue":"",
"wed":"",
"thu":"",
"fri":"",
}
So I could add all the classes hours to specific day key. But, there was a problem. For example lets say Programming lecture is subject 1 and Programming laboratories are subject 2. Subject 1 is on Monday at 9.15. Subject 2 is on Monday as well, but at 17.05. So I have a function, which would check if the subject is on even/odd week or it is every week. And then I would assign f.e 9.15 to even["mon"] on subject 1. Then I would go for subject 2, and tried to add 17.05 to even["mon"]. Every subject was an other Subject class object stored in a list. But there was a mistake. When I tried to add 17.05 to subject 2s even["mon"] it added it, okay, but then even["mon"] should ="17.05", but it was ="9.15/17.05". I was trying to figure out whats wrong, and I finally did, by changing my class from:
class Subject:
number = 0
name = ""
dummyData = []
even = {"mon":"",
"tue":"",
"wed":"",
"thu":"",
"fri":"",
}
...etc...
type = ""
def __init__(self, name, number, type):
self.name = name
self.number = number
self.type = type
self.info = str(number) + " " + name + " " + type
to:
class Subject:
number = 0
name = ""
dummyData = []
even = {}
odd = {}
all = {}
type = ""
def __init__(self, name, number, type):
self.name = name
self.number = number
self.type = type
self.info = str(number) + " " + name + " " + type
self.even = {"mon":"",
"tue":"",
"wed":"",
"thu":"",
"fri":"",
}
+ odd and all. So why is Python like remembering whats been written into the first object attributes?
You need to declare the attributes inside the __init__ method. Here's an example
class Subject:
def __init__(self, name, number, type):
self.number = number
self.name = name
self.dummyData = []
self.even = {}
self.odd = {}
self.all = {}
self.type = type
Declaring the variables inside the class declaration makes them "class" members and not instance members. Declaring them in the __init__ method makes ensures a new instance of the members is created every time you create a new instance of the object.
Related
I have a class (Student) with different attributes, such as studentId, address, and courses. My str method for the class returns all the information that the user put in. However, for the attributes that are lists, such as courses, the location of the information is printed out instead of the actual information. Here is the code (sorry it's a little long, there's a bunch of classes):
class Person:
__name = None
__age = None
__address = None
def __init__(self, name, age=0, address=None):
self.set_name(name)
self.set_age(age)
self.set_address(address)
def __str__(self):
return 'Name: ' + self.__name + '\n' + \
'Age: ' + str(self.__age) + '\n' + \
'Address: ' + str(self.__address)
def set_name(self, name):
self.__name = name
def get_name(self):
return self.__name
def set_age(self, age):
self.__age = age
def get_age(self):
return self.__age
def set_address(self, address):
self.__address = address
def get_address(self):
return self.__address
class Student(Person):
def __init__(self, name, studentID= None, age= 0, address= None):
super(Student, self).__init__(name, age, address)
self.set_studentID(studentID)
self.__courses =[]
def __str__(self):
result = Person.__str__(self)
result += '\nStudent ID:' + self.get_studentID()
for item in self.__courses:
result += '\n ' + str(item)
return result
def set_studentID(self, studentID):
if isinstance(studentID, str) and len(studentID.strip()) > 0:
self.__studentID = studentID.strip()
else:
self.__studentID = 'NA'
def get_studentID(self):
return self.__studentID
def add_course(self, course):
print('in add_course')
self.__courses.append(course)
def get_courses(self):
for i in range(len(self.__courses)):
return self.__courses[i]
class Course:
__courseName = None
__dept = None
__credits = None
def __init__(self, courseName, dept= 'GE', credits= None):
self.set_courseName(courseName)
self.set_dept(dept)
self.set_credits(credits)
def __str__(self):
return self.get_courseName() + '/' + self.get_dept() + '/' + str(self.get_credits())
def set_courseName(self, courseName):
if isinstance(courseName, str) and len(courseName.strip()) > 0:
self.__courseName = courseName.strip()
else:
print('ERROR: Name must be a non-empty string')
raise TypeError('Name must be a non-empty string')
def get_courseName(self):
return self.__courseName
def set_dept(self, dept):
if isinstance(dept, str) and len(dept.strip()) > 0:
self.__dept = dept.strip()
else:
self.__dept = "GE"
def get_dept(self):
return self.__dept
def set_credits(self, credits):
if isinstance(credits, int) and credits > 0:
self.__credits = credits
else:
self.__credits = 3
def get_credits(self):
return self.__credits
students = []
def recordStudentEntry():
name = input('What is your name? ')
age = input('How old are you? ')
studentID= input('What is your student ID? ')
address = input('What is your address? ')
s1 = Student(name, studentID, int(age), address)
students.append(s1)
s1.add_course(recordCourseEntry())
print('\ndisplaying students...')
displayStudents()
print()
def recordCourseEntry():
courses = []
for i in range(2):
courseName = input('What is the name of one course you are taking? ')
dept = input('What department is your course in? ')
credits = input('How many credits is this course? ')
c1 = Course(courseName, dept, credits)
print(c1)
courses.append(c1)
displayCourses(courses)
return courses
def displayCourses(courses):
print('\ndisplaying courses of student... ')
for c in range(len(courses)):
print(courses[c])
def displayStudents():
for s in range(len(students)):
print()
print(students[s])
recordStudentEntry()
This is how the code above prints out the 'displaying students...' part:
displaying students...
Name: sam
Age: 33
Address: 123 st
Student ID:123abc
[<__main__.Course object at 0x000002BE36E0F7F0>, <__main__.Course object at
0x000002BE36E0F040>]
I know that it is printing out the location because I need to index into the list. However, the length of the list will be different every time. Normally if I wanted to index into a list, for example, to print a list of names, I would do:
listOfNames = ['sam', 'john', 'sara']
for i in range(len(listOfNames)):
print(listOfNames[i])
or
listOfNames = ['sam', 'john', 'sara']
for i in listOfNames:
print(i)
(not sure what if any difference there is between the 2 ways since they both print out the same way:)
sam
john
sara
How can I write something like the indexing into a list technique shown here in my str method for my class so that it prints the information and not the location?
It would be good to keep to the standard conventions for Python, such as naming
private attributes for objects with single underscores, not double underscores.
The latter are reserved for Python "internal" attributes and methods.
Also, it is convention to use object attributes for objects with get/set methods,
not class attributes. This will make it easier to inspect your objects, while
still maintaining data hiding. Example:
class Course:
def __init__(self, courseName, dept= 'GE', credits= None):
self._courseName = None
self._dept = None
self._credits = None
self.set_courseName(courseName)
...
Your question about why the courses don't print out the way you expected
is rooted in a programming error with the way you programmed the recording
of courses. In recordCourseEntry(), you record two courses and put them
in a list. However, you pass that to your Student object using a method
intended for one course at a time. My suggested fix would be:
...
# s1.add_course(recordCourseEntry())
courses = recordCourseEntry()
for course in courses:
s1.add_course(course)
...
This will probably be enough to get you going. An example output I got was:
Name: Virtual Scooter
Age: 33
Address: 101 University St.
Student ID:2021
ff/GE/3
gg/GE/3
I am working on a program that takes in a CSV file of people and returns a population of the people. The file contains a table with the first name, last name, and 5 different traits (Work, Socialize, Hobbies, Eat, Sleep) of the people. Currently, I have a Person class that accepts the first and last name as strings and the traits as dictionaries. I am also defining if the person has an unbalanced or balanced life based on their distribution of the traits. The str method of this class is being used to return whether the person is unbalanced or balanced, but I also need to create a list called the population of the person objects, but it is returning the unbalanced or balance status of each person.
class Person:
def __init__(self, first_name, last_name, traits):
self.first_name = str(first_name)
self.last_name = str(last_name)
self.traits = traits
def determine_lifestyle(self):
check = 0
check2 = 0
if(self.traits["Sleep"] != 0 and self.traits["Eat"] != 0):
for val in self.traits.values():
if(val == 3):
check += 1
if(val == 2):
check2 += 1
if(check >= 3 or check2 >= 3):
return True
else:
return False
def __str__(self):
if(self.determine_lifestyle()):
return self.first_name + " " + self.last_name + " has a balanced lifestyle"
else:
return self.first_name + " " + self.last_name + " has an unbalanced lifestyle"
import csv
def read_file(filename):
f = open(filename, 'r')
population = []
reader = csv.reader(f)
next(reader)
for row in reader:
population.append((row[0],row[1],{"Work":row[2],"Hobbies":row[3],"Socialize":row[4],"Eat":row[5],
"Sleep":row[6]}))
return population
Is there any way to return the person object without using the str method?
Your code seems incomplete, as your population variable is holding tuples, instead of Person object instances.
If you have a list of Person instances, and then you print those instances, their unbalanced or balanced status would show up, as print would print the string representation of the instance, and the representation is overwritten as you define a __str__() method for the class.
Is there any way to return the person object without using the str method?
If you instantiate a Person object, like aperson = Person(fname, lname, traits), then you could get attributes of it though aperson.first_name, aperson.last_name, and get its balance status using `aperson.determine_style
I am using eval to run a generated string to append the newly created EggOrder instance to the list of the correct instance of the DailyOrders class. The day provided by EggOrder is used to used to append to the correct instance. This relies on eval and the variable name of the DailyOrders instance and so it would be great to get this removed. I know there must be a better way.
class DailyOrders:
PRICE_PER_DOZEN = 6.5
def __init__(self, day):
self.orders = []
self.day = day
def total_eggs(self):
total_eggs = 0
for order in self.orders:
total_eggs += order.eggs
return total_eggs
def show_report(self):
if self.total_eggs() < 0:
print("No Orders")
else:
print(f"Summary:\nTotal Eggs Ordered: {self.total_eggs()}")
print(f"Average Eggs Per Customer: {self.total_eggs() / len(self.orders):.0f}\n*********")
class EggOrder():
def __init__(self, eggs=0, name="", day=""):
if not name:
self.new_order()
else:
self.name = name
self.eggs = eggs
self.day = day
eval(f"{self.day.lower()}.orders.append(self)")
def new_order(self):
self.name = string_checker("Name: ")
self.eggs = num_checker("Number of Eggs: ")
self.day = string_checker("Date: ")
def get_dozens(self):
if self.eggs % 12 != 0:
dozens = int(math.ceil(self.eggs / 12))
else:
dozens = self.eggs / 12
return dozens
def show_order(self):
print(f"{self.name} ordered {self.eggs} eggs. The price is ${self.get_dozens() * DailyOrders.PRICE_PER_DOZEN}.")
if __name__ == "__main__":
friday = DailyOrders("Friday")
friday_order = EggOrder(12, "Someone", "Friday")
friday_order.show_order()
friday.show_report()
saturday = DailyOrders("Saturday")
saturday_order = EggOrder(19, "Something", "Saturday")
saturday_order = EggOrder(27, "Alex Stiles", "Saturday")
saturday.show_report()
DailyOrders isn't actually a superclass (it was in a earlier version), it acts like one and I suspect the answer might have some inheritance.
class City(Object):
symbol = "1"
name = "City"
priority = 30 # Should actually be above mob layer.
size = 5
starting_citizens = 5
citizens = []
resources = {"food" : 100,
"wood" : 0,
"iron" : 0}
inventory = []
needs_processing = True
action_time = 6
def __init__(self, loc, x, y):
global log
log = log + "A new town has been settled!\n"
self.name = self.name + " " + str(random.randrange(1, 999))
super().__init__(loc, x, y)
print(len(self.citizens))
print("Procedure undergoing in: " + self.name)
for N in range(self.starting_citizens - 1):
print("Another one bites the city")
self.add_citizen(Peasant)
print("CITY INIT END")
print(len(self.citizens))
print(self.citizens)
def add_citizen(self, citizen_type):
print("Procedure undergoing in: " + self.name)
print(str(len(self.citizens)) + " before adding occured")
self.citizens.append(citizen_type(self, -2, -2)) #Huehuehue. -2 -2 won't be qdeled.
print(str(len(self.citizens)) + " after adding occured")
For any amount of reasons, all class City objects share the citizens list. It is identical in each one, what is not something I would like. I would like to have each Class have it's own list.
No amount of debugging helped me see the problem.
http://prntscr.com/kgz5as
That is because you defined your citizens list to be a class variable instead of an instance variable. It is therefore being shared between all instances. (See 9.3.5 in the Docs page on classes)
You actually have multiple variables that should probably be instance variables instead of being shared by all isntances of the class (like citizens, size, name etc.). Define them as isntance variables instead like so:
def __init__(self, loc, x, y):
self.citizens = []
Me very very new programmer, I'm new to classes and not sure how to set up a print method for this class. How do I go about setting up a print method for my class here? Thanks for anything!
class travelItem :
def __init__(self, itemID, itemName, itemCount) :
self.id = itemID
self.name = itemName
self.itemCount = itemCount
self.transactions = []
def getID(self) :
return(self, id)
def getName(self) :
return(self.name)
def setName(self, newName) :
self.name = newName
def getAvailableStart(self):
return(self.AvailableStart)
def appendTransaction(self, num) :
self.transactions.append(num)
def getTransactions(self) :
return(self.transactions)
def getReservations(self) :
Additions = 0
for num in self.transactions :
if (num > 0) :
Additions = Additions + num
return(Additions)
def getCancellations(self) :
Subtractions = 0
for num in self.transactions :
if (num < 0) :
Subtractions = Subtractions + num
return(Subtractions)
def getAvailableEnd(self) :
total = self.AvailableStart
for num in self.transactions :
total = total + num
return(total)
Remember that a method is called on an instance of a class, so if you mean to create a true method that just prints a class you can write something like
class Foo(object):
def print_me(self):
print(self)
foo_instance= Foo()
foo_instance.print_me()
But it sounds like you want to customize the output of print(). That is what the built in method __str__ is for, so try this.
class Foo(object):
def __str__(self):
# remember to coerce everything returned to a string please!
return str(self.some_attribute_of_this_foo_instance)
a good example from your code might be
...
def __str__(self):
return self.getName + ' with id number: ' + str(self.getId) + 'has ' + str(self.getTransactions) + ' transactions'
You must use a __str__ special method:
class travelItem:
...
def __str__(self):
return "a string that describe the data I want printed when print(instance of class) is called"