Search code examples
pythonpython-3.xoopinstance-variables

How to print the "instantiated" variable in Python OOP?


I am studying the book "Learn Python the Hard Way" with Python3. The author presented the concept of OOP with this example:

class Song (object):

    def __init__(self,lyrics):
        self.lyrics = lyrics

    def sing_me_a_song(self):
        for line in self.lyrics:
            print (line)


happy_bday = Song(["Happy birthday to you", "I don't want to get sued","So I'll stop right there"])

bulls_on_parade = Song(["They rally around the family","With pockets full of shells"])

happy_bday.sing_me_a_song()

bulls_on_parade.sing_me_a_song()

OOP is kind of funny to me. The author suggest that we should "trash", "break" and "thrash" the code above a little bit.

I was trying to print the variable name in which the object was "instanced" (not sure if "instanced" is the correct word here, maybe the correct word is "instantiated"). In order to try that, I added the following methods on the class Songs():

class Song (object):

    def __init__(self,lyrics):
        self.lyrics = lyrics

    def sing_me_a_song(self):
        for line in self.lyrics:
            print (line)

    def name_of_var(self):
        print (Song)

    def name_of_var_2(self):
        print (object)

    def name_of_var_3(self):
        print (self)

    def name_of_var_3(self):
        print (self)

I used the examples of objects provided by the author:

happy_bday = Song(["Happy birthday to you", "I don't want to get sued","So I'll stop right there"])

bulls_on_parade = Song(["They rally around the family","With pockets full of shells"])

happy_bday.sing_me_a_song()

bulls_on_parade.sing_me_a_song()

Finally, I tried doing:

print(Song(["They rally around the family","With pockets full of shells"]))

print (happy_bday.name_of_var())

print (happy_bday.name_of_var_2())

print (happy_bday.name_of_var_3())

print (happy_bday.__init__(happy_bday))

I wasn't able to achieve my goal. Using the methods above I got:

<__main__.Song object at 0x7f4b784f3da0>
<class '__main__.Song'>
None
<class 'object'>
None
<__main__.Song object at 0x7f4b784f3d30>
None
None
pedr

My objective was to create some method in which I would do:

print (happy_bday.__some__method())

And the program would return:

happy_bday

Maybe that's not even possible in Python... If I am not wrong, you can do this type of thing in Lisp/Racket (but I am not 100% sure). Is this possible in Python? How can I do that?


Solution

  • What's confusing you is that an object doesn't actually have a name! Let's say we create a Song using the Song constructor, and put it in a variable called happy_bday:

    happy_bday = Song(["Happy birthday to you", "I don't want to get sued","So I'll stop right there"])
    

    This creates a Song object, which lives on "the heap," an area of memory in your computer. It also creates a variable called happy_bday, which refers to the Song object you've just created. The Song object itself doesn't know this, though.

    In fact, if you run

    happy_bday2 = happy_bday
    

    you will create another variable, happy_bday2, that refers to the exact same Song object. In fact, if you were to now run the line

    happy_bday.lyrics[0] = "Happy Birthday To You"
    

    to add some capitalization, the lyrics of happy_bday2 would also change. That's because even though you have two separate variables, they are really just two ways of referring to the exact same object in memory.

    Hopefully, it's now clear why you can't ask the Song object what variable refers to it; there could be multiple variables that refer to it, or no variables at all (after all, you could just write Song(["some lyrics"]).var_name(), in which case, what should be printed out?).

    If you'd like to visualize this, there's a great tool called PythonTutor available here: http://pythontutor.com. You can type in your code, and see the variables and objects that are being created.