A tip: in python do not think about objects that are created or destroyed, rather think about objects that you access through their name, a mere label with which you indicate to the interpreter what he has to do.
Everything you see about "creation of variables" or "assignment of variables" is an inheritance of how you thought in other languages. In python they "give names" .
For following your example:
a = 2
a = "Hola"
To the object of type integer
2 we identify it with the name
a . Then, to the object string
"Hola" we identify it with the name
a . The only thing you can guarantee now is that the name
a identifies the string
"Hola" ; you can not know what happened to the
2 object. It is possible that it was referencing with another name and that it can not be deleted. It is also possible that, being such a common object, it is always available in memory. In python, all numbers from -5 to 256 exist in memory, although no one uses them, for optimization reasons.
One way to confirm it:
[i for i in range(-100,300) if id(i)==id(i+0)]
id() returns a unique identifier for each object. If two objects have the same identifier, they are the same object.
With chains, something more curious happens:
id("hola2")==id("hola"+"2") # -> True
id("hola 2")==id("hola "+"2") # -> False
This behavior corresponds to an automatic process of "internalization of strings" used in the optimizations of the interpreter. This process caches all the character strings present in the code that comply with the variable naming rules. In the previous case,
hola2 could serve as the name of one variable,
hola 2 no. Any internalized string will never be deleted , even if it is not referenced.
To conclude, let's look at the last case:
a = 2
b = a
a = "Hola"
Here, what is done is to give another name,
b , to the object pointed to
a . Nothing is created, nothing is destroyed.
Entering at a lower level, it is not the GC that destroys the objects. The objects have a reference counter so that, when this counter reaches zero, they self-destruct.
The GC is an instrument that the interpreter has to free memory in certain complex cases to detect, such as circular references :
a = 
b = [a]
Here we have created two lists that self-reference and then we have deleted our references. Although we have no way to access these lists, they are referencing each other, so their reference counters never reach zero. It must be the GC who is responsible for checking that there is no other object that needs them and deletes them from memory.