print object/instance name in python

Question:

I was wondering if there is a way to print the object name in python as a string. For example I want to be able to say ENEMY1 has 2 hp left or ENEMY2 has 4 hp left. Is there a way of doing that?

class badguy:
    def __init__(self):
        self.hp = 4

    def attack(self):
        print("hit")
        self.hp -= 1

    def still_alive(self):
        if self.hp <=0:
            print("enemy destroyed")
        else :
            print (str(self.hp) + " hp left")

    # creating objects

    enemy1 = badguy()
    enemy2 = badguy()

    enemy1.attack()
    enemy1.attack()
    enemy1.still_alive()
    enemy2.still_alive()
Asked By: netrate

||

Answers:

You’d have to first give them names. E.g.

class badguy:
    def __init__(self, name):
        self.hp = 4
        self.name = name

    def attack(self):
        print("hit")
        self.hp -= 1

    def still_alive(self):
        if self.hp <=0:
            print("enemy destroyed")
        else :
            print (self.name + " has " + str(self.hp) + " hp left")

    # creating objects

    enemy1 = badguy('ENEMY1')
    enemy2 = badguy('ENEMY2')

    enemy1.attack()
    enemy1.attack()
    enemy1.still_alive()
    enemy2.still_alive()
Answered By: user94559

A much better design principle is not to rely on the specific name of the object as shown below:

class badguy(object):
    def __init__(self):
        pass

b = badguy()
print b
>>> <__main__.badguy object at 0x7f2089a74e50>  # Not a great name huh? :D

This can lead to a whole wealth of issues with assignment binding, referencing, and most importantly does not allow you to name your objects per user or program choice.

Instead add an instance variable to your class called self._name (9.6 Classes – Private Variables) or self.name if you want to allow access outside the scope of the class (in this example, you can name it anything). Not only is this more Object-Oriented design, but now you can implement methods like __hash__ to be able to create a hash based on a name for example to use an object as a key (there are many more reasons why this design choice is better!).

class badguy(object):
    def __init__(self, name=None):
        self.hp = 4
        self._name = name   

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name):
        self._name = name

    def attack(self):
        print("hit")
        self.hp -= 1

    def still_alive(self):
        if self.hp <=0:
            print("enemy destroyed")
        else :
            print ("{} has {} hp left.".format(self.name, self.hp))

Sample output:

b = badguy('Enemy 1')
print b.name
>>> Enemy 1

b.still_alive()
>>> Enemy 1 has 4 hp left.

b.name = 'Enemy One'  # Changing our object's name.
b.still_alive()
>>> Enemy One has 4 hp left.
Answered By: ospahiu

I have posted a complete solution here:

https://stackoverflow.com/a/49331683/7386061

It works without parameters. For example you could just do:

class badguy(RememberInstanceCreationInfo):
    def __init__(self):
        super().__init__()
        self.hp = 4

    def attack(self):
        print("hit")
        self.hp -= 1

    def still_alive(self):
        if self.hp <=0:
            print("enemy destroyed")
        else :
            print (self.creation_name + " has " + str(self.hp) + " hp left")

enemy1 = badguy()
enemy2 = badguy()

enemy1.attack()
enemy1.attack()
enemy1.still_alive()
enemy2.still_alive()

out: hit
out: hit
out: enemy1 has 2 hp left
out: enemy2 has 4 hp left
Answered By: TheoRet

Probably not something you’d want to rely on, but this is what I have if you’d like to mess around with it. Tested using python 3.11.0.

from inspect import currentframe, getframeinfo
from math import pi

class Circle:
    def __init__(self, radius):
        self.radius = radius
        
    def __call__(self):
        print(f'{self.get_caller_name()} called itself.')

    def area(self):
        print(f'{self.get_caller_name()} called area().')
        return pi * self.radius ** 2

    def get_caller_name(self):
        caller_frame = currentframe().f_back.f_back
        caller_locals = caller_frame.f_locals
        for name, obj in caller_locals.items():
            if obj is self:
                return name
        print("Could not determine the name referencing this instance.")
}

c1 = Circle(2)
c1()
c1.area()

Outputs:

> c1 called itself.
> c1 called area().
Answered By: ThinkingInBits
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.