Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python Object-Oriented Python (retired) Inheritance __str__

Iskander Ismagilov
Iskander Ismagilov
13,298 Points

How can I print instance name?

What do I need to write in str method for printing instance name? For example:

draco = Dragon(()

print(draco) -> Draco is Blue Dragon HP: 5 XP: 6

2 Answers

Hi Iskander,

I don't think that you can do that. The Dragon instance does not have any knowledge that it's been assigned to a variable named draco

If you'd like to name the monsters then you have to handle the naming yourself. You can pass the name in when you create the instance.

The __init__ method already provides for a variable number of keyword arguments to be assigned as attributes with the for loop so you don't have to make any change there.

  def __init__(self, **kwargs):
    self.hit_points = random.randint(self.min_hit_points, self.max_hit_points)
    self.experience = random.randint(self.min_experience, self.max_experience)
    self.color = random.choice(COLORS)

    for key, value in kwargs.items():
      setattr(self, key, value)

This means you can do

draco = Dragon(name="Draco")

and the instance will have a name attribute.

Then it's a matter of updating __str__ to use this added name attribute.

  def __str__(self):
    return '{} is {} {}, HP: {}, XP: {}'.format(self.name,
                                                self.color.title(),
                                                self.__class__.__name__,
                                                self.hit_points,
                                                self.experience)

In this case, you always have to name the monster so you don't get any errors. It might be more flexible to make the name optional. Here's one way you could rewrite the str method to make naming the monster optional:

def __str__(self):
    output = '{} {}, HP: {}, XP: {}'.format(self.color.title(),
                                            self.__class__.__name__,
                                            self.hit_points,
                                            self.experience)

    if hasattr(self, 'name'):
      output = self.name + " is " + output

    return output

You can check if the name attribute exists and add it to the output before returning.

Here's some example console output showing the optional name:

>>> from monster import Dragon                                                                                  
>>> draco = Dragon()                                                                                            
>>> print(draco)                                                                                                
Red Dragon, HP: 8, XP: 7                                                                                        
>>> draco = Dragon(name="Draco")                                                                                
>>> print(draco)                                                                                                
Draco is Red Dragon, HP: 6, XP: 10                                                                              
>>>
Chris Freeman
Chris Freeman
Treehouse Moderator 68,454 Points

Great answer Jason! It got me to think of it from another viewpoint: the right-hand side of the statement has no knowledge of the left-hand side. So Dragon has no idea to which variable name it will be assigned to. It runs through its creation process then returns an object. It's the left-hand side of the statement that assigns this object to the name variable draco. So to get the intended variable name accessible to the constructor, you need to pass the intended variable name to the constructor as you mentioned. :+1:

Thanks Chris.

Iskander Ismagilov
Iskander Ismagilov
13,298 Points

Thanks Jason. It's very helpful. Escpecially make name attribute optional using hassattr function. I should pay attention on that attribute before.

Chris Freeman
MOD
Chris Freeman
Treehouse Moderator 68,454 Points

Since you need to know the instance name to access the attributes, you type it as a literal string. For the class name use

class Dragon():
    hit_points = 5
    experience_points = 6
    color = "Blue"

draco = Dragon()

print("Draco is {} {} HP: {} XP: 6".format(
    draco.color, draco.__class__.__name__,
    draco.hit_points, draco.experience_points))

# Draco is Blue Dragon HP: 5 XP: 6
Chris Freeman
Chris Freeman
Treehouse Moderator 68,454 Points

Rereading the OP, I realize this doesn't address the actual question. Upvoting Jason answer.