Namespaces have names.
Names refer an object.
Every object is referred by one or more name in one or more namespaces.
Names cannot exists alone without referring an object.
By using sys.getrefcount(), we can get how many time an object is being referred by names in different namespaces. For example:
import sys
sys.getrefcount(None)
By this Jupyter interpretor, None is referred 26851 times in different namespaces with different names. To get all the namespaces used by the interpreter, we can use dir() function.
dir()
Let's filterout the output to remove cluter.
def _dirn(_CLUTTER=dir()):
print('{:8} {:4} @ {}'.format('Name','Value', 'Id'))
print('\n'.join([
f'{k:8} {v:4} @ {id(v)}'
for (k,v) in globals().items()
if k not in _CLUTTER and not k.startswith('_')
]))
The above helper function remove names that have been created by the interpreter before.
_dirn
After filtering out, we do not currently have any namespace.
_dirn()
Let us create a name without assigning any object to it. What happens?
number2
Python cannot find the name number2 in any namespace. Let us assign an number object to it and see.
number2 = 900
_dirn()
When number2 is assigned value 900 with "=" operator, it is merely name binding operation of the number object 900. If the number object 900 does not already exist, then the object is created at this step. Let us try this:
number3 = 900
_dirn()
Above, we can see that the names number2 and number3 are assigned different ids which indicates that the number objects 900 are different. To further prove, check this out:
id(900)
id(900)
Above, the 900s are different number objects. However, when the value of one name is assigned to another name, no new object is created and ids are same.
number4 = number2
_dirn()
Above, the id for number2 and number4 are same which indicates that the same number object 900 is being referenced by both number2 and number4. This is the reason we are not able to use a copy of, for example, a list object input to a function instead of manipulating the original list object inside the function. Check this out:
#don't worry about the absurdness of the function and the logic, the purpose is just to show that you cannot copy
#an object with simple operation
def remove_zeros(listinput):
listoutput = listinput
for i in listoutput:
if i == 0:
listoutput.remove(i)
return listinput, listoutput
remove_zeros([0,1,0,1,0,1,0])
We can see above that the removal of zeros happened in the same object.
On the other hand, what happens to an object that is assigned to a name when the name refers some other object. Let us assign different value to number2
number2 = 400
number2
number4
Above, the object 400 is referred by the name number2 but the name number4 still refers the same object. This is kind of putting multiple name tags on the object. When you remove a name tag and put it on another object, then that name refers to that new object. Let us check the id of the objects 400 and 900.
id(number2)
id(number4)
While id of number4 remains same, id of number2 has been changed. If we change the value of number4 too, the integer object 900 left without any name refernece.
number4 = 500
id(number4)
From this point onwards, we wont be able to access the integer object 900 with id 140709459354544 anymore. Let us continue with namespaces in the next part.
Reference: Stuart Williams - Python Epiphanies - PyCon 2018 https://www.youtube.com/watch?v=-kqZtZj4Ky0&t=498s