Print data from Class instance - python

I want to print out data from a Class instance. I tried including data in str function, but this only works when value is at its default (an empty list). After I've added data to the list, I can only get memory objects printed. Can anyone help me troubleshoot why this is happening? I want to be able to print out objects to use in debugging.
class Student():
def __init__(self,name,year):
self.name=name
self.year=year
self.grades=[]
def add_grade(self, grade):
if type(grade)==Grade:
self.grades.append(grade)
else:
pass
def __str__(self):
return str(self.grades)
pieter=Student("Pieter Bruegel the Elder", 8)
print(pieter)
[] # Returns empty list of grades as it was initiated.
class Grade():
minimum_passing=65
def __init__(self,score):
self.score=score
def is_passing(self):
if self.score >= self.minimum_passing:
return True
else:
return False
pieter.add_grade(Grade(100))
pieter.add_grade(Grade(40))
print(pieter)
[<__main__.Grade object at 0x000002B354BF16A0>, <__main__.Grade object at 0x000002B354BF13A0>]

When you tell it to print 'pieter', you are telling it to attempt to print the object. What you need to do is add a print function in the class or use the specific variable in the object. Try adding something like this:
def print_object(self):
print("The name is: {self.name}")
print("The year is: {self.year}")
print("The grades are: {self.grades}")
If you have any questions, please feel free to reach out.

The list.__str__() method uses repr() to get the representation of the list elements. So this is showing the repr() of all the Grade objects in the grades list. Since Grade doesn't have a custom __repr__() method, you get the default representation.
You could define Grade.__repr__() to specify how you want grades to appear, or you could change the Student.__str__() method to get the scores from the Grade objects in the list.
class Student():
def __init__(self,name,year):
self.name=name
self.year=year
self.grades=[]
def add_grade(self, grade):
if isinstance(grade, Grade):
self.grades.append(grade)
else:
pass
def __str__(self):
return str([str(g) for g in self.grades])

The problem is that Grade itself doesn't have a neat representation as a string. Thus the str(self.grades) call can only print a list of abstract instance data. You could include a representation:
class Grade():
# the other stuff goes here...
def __repr__(self):
return f'Grade({self.score}'
Now print(pieter) prints:
[Grade(100), Grade(40)]
However, I wouldn't use the __str__() magic method to print the grades. It's clearer to define an explicit method such as print_grades() for this purpose. __str__() is normally used to output all the relevant information about a class (for debug purposes etc.) So in your case, it should return all the student info too, not just the grades.

In your add_grade method, you are inserting a Grade object into self.grades, and then when you print self.grades you get a list of Grade objects. Maybe you want to insert the score field from the Grade object into self.grades. That way you can print out the scores when you print out a student. Like so:
def add_grade(self, grade):
if type(grade) == Grade:
self.grades.append(grade.score)
Also, there is no need to write the else statement in the method, it will automatically return None if the argument passed to it is not a Grade object.

Related

How to put all objects of a class into a list

I want to make a list of all the names that are given in a class this is the code right now I’m getting the error that is none type I feel like the append isn’t working
class Names:
def __init__(self,name):
self._name = name
self._list_name= []
def make_list(self,name):
self._list_name.append(name)
def __str__(self):
for i in self._list_name:
return i
You shouldn't return inside the loop. That will just return the first name in the list. And if you call __str__() before you call make_list(), there won't be anything in the list. The loop won't run and the method will return None, which is invalid for the __str__() method.
Instead, concatenate all the names into a string.
class Names:
def __init__(self,name):
self._name = name
self._list_name= []
def make_list(self,name):
self._list_name.append(name)
def __str__(self):
return ', '.join(self._list_name)
BTW, the name make_list doesn't really describe what that method does. It doesn't make a list, it adds to the list. Call it something like add_name().
I don't know how you plan on using this, but you might want to include the initial name in the list, so change
self._list_name = []
to
self._list_name = [name]

Instantiating object and using class definition __init__

so for this piece of code, the program has to instantiate the object "acc1" where acc1 = BankAccount(1000), where 1000 is the balance. Using the class definition for Bank Account, and using a display method, acc1.display(), the code should print "balance=1000". My code is printing the balance is part, but not taking into account the 1000 part.
class BankAccount:
def __init__ (self,balance):
self.balance = balance
acc1 = BankAccount("1000")
acc1.display()
print("Balance=",acc1,sep="")
You are trying to print the object itself rather than its balance. You will get the default value printed for the BankAccount class (something like <__main__.BankAccount object at 0x7f2e4aff3978>).
There are several ways to resolve the issue:-
First print just the balance property
print("balance=",acc1.balance,sep="")
If you want to modify the class you can define the display method. This isn't ideal as it limits the way the display information can be used. It has to be displayed to standard out, it cant be joined to other strings etc. It is less flexible.
It would be better to define __str__ and return the display string which can be displayed, concatenate etc.
class BankAccount:
def __init__ (self,balance):
self.balance = balance
def display(self):
print('balance=%s' % self.balance)
def __str__(self):
return 'balance=%s' % self.balance
acc1 = BankAccount("1000")
acc1.display() # use display
print(acc1) # use __str__

Unintuitive output given by classes in Python

So I've got this class:
class Student(object):
def __init__(self, studentID, name):
self.__studentID = studentID
self.__name = name
def set_studentID(self, value):
self.__studentID = value
def get_name(self):
return self.__name
and running this code:
x = Student
x.set_name(x, input("Name: "))
x.set_studentID(x, len(students))
students.append(copy.deepcopy(x))
x.set_name(x, input("Name: "))
x.set_studentID(x, len(students))
students.append(copy.deepcopy(x))
for i in (students):
print(i.get_name(i))
gives an unexpected output:
For the input:
a
b
the output is:
b
b
The expected output is:
a
b
If you answer please give me a short explanation of why it doesn't work
The reason your code isn't working is because you never instantiate your class, instead, you assign the class object itself to the name x
x = Student
When you really needed
x = Student()
Then you call the methods on the class object, whilst passing the class object itself as the first parameter, thus your getters and setters act on the class object.
Finally, classes are meant to be singletons, and the copy module special cases them. So if x is a class
copy.deepcopy(x) is x
Is always True, thus you never actually make a copy.
As a side note, your class definition looks like it was written by a Java developer using Python for the first time. The Pythonic way to do it is not to use getters and setters use properties, and only when you need to. Also, don't use double-underscores name-mangling unless you actually want that, which in this case, you dont.
The other answer explains why your code doesn't work as you expect it to. Here's how you could rewrite your code in a more pythonic way.
class Student(object):
def __init__(self, studentID, name):
self.studentID = studentID
self.name = name
students = []
name = input("Name: ")
students.append(Student(len(students), name))
name = input("Name: ")
students.append(Student(len(students), name))
for student in students:
print(student.name)
You don't need to write getter and setter methods unless you have to do some special processing.

Alphabetizing a list through class methods

I have been trying to print a list using a __str__ method of a class, but before the list can be printed it has to be alphabetized through other methods coming before the __str__ method in the class. The provided methods for this are:
def returnName(self):
'''return the name of the player first last'''
return(self.first + self.last)
def returnReverseName(self):
'''return the name of the player as last, first'''
reverseName = (str(self.last), str(self.first))
return(reverseName)
def __eq__ (self, other):
'''determine if this persons name is the same as the other personsname'''
if self.returnReverseName == other.returnReverseName:
return True
else:
return False
def __lt__(self,other):
'''determine if this persons name is less than the other persons name alphabetically'''
if str(self.returnReverseName) < str(other.returnReverseName):
return True
else:
return False
def __gt__ (self, other):
'''determine if this persons name is greater than the other persons name alphabetically'''
if self.returnReverseName > other.returnReverseName:
return True
else:
return False
def __str__(self):
'''return a string of the persons name and their rating in a nice format'''
Name1 = str(self.first) + ' ' + str(self.last)
return ('%-20s %10.2f' % (Name1, self.rating))
where the name needs to be sorted by last name, first name but printed in first name last name order. The methods __lt__ and __gt__ are what should be ordering them when printed. The code I have so far to compile the list is:
basicList.sort()
for line in playerDict:
print(playerDict[line])
but this doesn't utilize the list, and is only printing the dictionary line by line in an unordered manner. Although it does refer to the methods it is just unable to alphabetize the names. How do I properly use the methods to get the dictionary printed in the right order? If I need to use the list of player objects, how do I get it to print using the __str__ method that would be printed post-alphabetization?
This code has many mistakes and oddities, but the first thing it does that could actually cause wrong results is that __eq__ and __gt__ are comparing two functions rather than two names. __lt__, for some reason, compares the string representations of those two functions. I don't know why it has different behavior than the other functions, but it's still wrong (just in a different way).
And I'm not surprised that the sorted list isn't used - you never use it.
basicList.sort() # sort the list
for line in playerDict: # that's not basicList
print(playerDict[line]) # still no basicList
Your class methods, if repaired, might look like this:
def returnName(self):
'''return the name of the player first last'''
return(self.first + ' ' + self.last)
def returnReverseName(self):
'''return the name of the player as last, first'''
return self.last, self.first
def __eq__ (self, other):
'''determine if this persons name is the same as the other personsname'''
return self.returnReverseName() == other.returnReverseName()
def __lt__(self,other):
'''determine if this persons name is less than the other persons name alphabetically'''
return self.returnReverseName() < other.returnReverseName()
def __gt__ (self, other):
'''determine if this persons name is greater than the other persons name alphabetically'''
return self.returnReverseName() > other.returnReverseName()
def __str__(self):
'''return a string of the persons name and their rating in a nice format'''
return '%-20s %10.2f' % (self.returnName(), self.rating)
But you probably don't need any of that. It looks like playerDict is a dictionary that holds some kind of keys attached to values that are Player objects (I assume that's the class name). Just iterate over those values and use a given sort key:
for entry in sorted(playerDict.values(), key=lambda x: x.last, x.first):
print(entry)

typecast classes in python: how?

Here, I am attempting to mock up a social media profile as a class "Profile", in which you have name, a group of friends, and the ability to add and remove friends. There is a method that I would like to make, that when invoked, will print the list of friends in alphabetical order.
The issue: I get a warning that I cannot sort an unsortable type. Python is seeing my instance variable as a "Profile object", rather than a list that I can sort and print.
Here is my code:
class Profile(object):
"""
Represent a person's social profile
Argument:
name (string): a person's name - assumed to uniquely identify a person
Attributes:
name (string): a person's name - assumed to uniquely identify a person
statuses (list): a list containing a person's statuses - initialized to []
friends (set): set of friends for the given person.
it is the set of profile objects representing these friends.
"""
def __init__(self, name):
self.name = name
self.friends = set()
self.statuses = []
def __str__(self):
return self.name + " is " + self.get_last_status()
def update_status(self, status):
self.statuses.append(status)
return self
def get_last_status(self):
if len(self.statuses) == 0:
return "None"
else:
return self.statuses[-1]
def add_friend(self, friend_profile):
self.friends.add(friend_profile)
friend_profile.friends.add(self)
return self
def get_friends(self):
if len(self.friends) == 0:
return "None"
else:
friends_lst = list(self.friends)
return sorted(friends_lst)
After I fill out a list of friends (from a test module) and invoke the get_friends method, python tells me:
File "/home/tjm/Documents/CS021/social.py", line 84, in get_friends
return sorted(friends_lst)
TypeError: unorderable types: Profile() < Profile()
Why can't I simply typecast the object to get it in list form? What should I be doing instead so that get_friends will return an alphabetically sorted list of friends?
Sorting algorithms look for the existence of __eq__, __ne__, __lt__, __le__, __gt__,__ge__ methods in the class definition to compare instances created from them. You need to override those methods in order to tweak their behaviors.
For performance reasons, I'd recommend you to define some integer property for your class like id and use it for comparing instead of name which has string comparison overhead.
class Profile(object):
def __eq__(self, profile):
return self.id == profile.id # I made it up the id property.
def __lt__(self, profile):
return self.id < profile.id
def __hash__(self):
return hash(self.id)
...
Alternatively, you can pass a key function to sort algorithm if you don't want to bother yourself overriding those methods:
>>> friend_list = [<Profile: id=120>, <Profile: id=121>, <Profile: id=115>]
>>> friend_list.sort(key=lambda p: p.id, reverse=True)
Using operator.attrgetter;
>>> import operator
>>> new_friend_list = sorted(friend_list, key=operator.attrgetter('id'))
I think i'll take a crack at this. first, here's teh codes:
from collections import namedtuple
class Profile(namedtuple("Profile", "name")):
def __init__(self, name):
# don't set self.name, it's already set!
self.friends = set({})
self.statuses = list([])
# ... and all the rest the same. Only the base class changes.
what we've done here is to create a class with the shape of a tuple. As such, it's orderable, hashable, and all of the things. You could even drop your __str__() method, namedtuple provides a nice one.

Categories

Resources