While executing the following code:
class Test():
    def __init__(self):
        self.hi_there()
        self.a = 5
    def hi_there(self):
        print(self.a)
new_object = Test()
new_object.hi_there()
I have received an error:
Traceback (most recent call last):
  File "/root/a.py", line 241, in <module>
    new_object = Test()
  File "/root/a.py", line 233, in __init__
    self.hello()
  File "/root/a.py", line 238, in hello
    print(self.a)
AttributeError: 'Test' object has no attribute 'a'
Why do we need to specify the self inside the function while the object is not initialized yet? The possibility to call hi_there() function means that the object is already set, but how come if other variables attributed to this instances haven't been initialized yet? 
What is the self inside the __init__ function if it's not a "full" object yet?
Clearly this part of code works:
class Test():
    def __init__(self):
        #self.hi_there()
         self.a = 5
         self.hi_there()
    def hi_there(self):
       print(self.a)
new_object = Test()
new_object.hi_there()
I come from C++ world, there you have to declare the variables before you assign them.
I fully understand your the use of self. Although I don't understand what is the use of self inside__init__() if the self object is not fully initialized.
 
     
     
     
    