Consider a situation where you have two cousins with the same name ‘ John’. If someone asks you to call ‘John’, what will be your immediate question? ‘Which John?’. Because just ‘Calling John’ is too ambiguous. If You are asked to call ‘John who lives in New York’ or ‘John who works at company XYZ’ etc. your job becomes simpler right? It simply means that the calling becomes easier after each John is identified differently.
Same situation occurs with compiler or interpreter of a language when there are two methods or variables with exactly same composition. This is where the Namespaces come into the picture. Namespaces define the region or context with which methods or variables with same names will be identified separately. Namespaces are recognized by their unique names.
Namespaces in Python are implemented as dictionaries or maps, where there is a key and a corresponding variable. This happens behind the scene so nothing is usually visible to the developer. Following are examples/types of Namespaces in Python
Let’s consider a command name.attributeMethod() official python documentation mentions anything that comes after dot as attribute. So ‘name‘ in this case is Namespace and attributeMethod() is the attribute accessed through object name. Namespaces and Scopes must not be confused here !
Most common example where ambiguity comes into picture while coding in Python is when there are two different modules having same method names or two packages with same module names and same method names. I would like to explain Namespaces in Python for these situations.
Let’s consider we have two methods with same name as getName() in two different modules module1.py and module2.py which returns different name.
# module1.py def getName(): return 'First Module'
# module2.py def getName(): return 'Second Module'
Now, let’s try to implement these methods
# myModule.py from module1 import * from module2 import * def callGetName(): getName() print(callGetName()) #This will print 'Second Module'
# myModule.py from module2 import * from module1 import * def callGetName(): getName() print(callGetName()) #This will print 'First Module'
So it is evident that, the getName() from the module from which everything is import LAST gets called. So, this method is useless in this situation if you have methods or variables with the same names in different modules.
2. Using from <module> import <method/variable> (Still Bad Way)
# myModule.py from module1 import getName from module2 import getName def callGetName(): getName() print(callGetName()) #This will print 'Second Module'
# myModule.py from module2 import getName from module1 import getName def callGetName(): getName() print(callGetName()) #This will print 'First Module'
Again it is evident that, the getName() from the module from which everything is import LAST gets called. So, this method is also useless in our situation.
In both the situations mentioned above, python interpreter overrides the definition of getName(). But, how can we re-write the code so that each getName() method can be called separately.
So, what is the solution to this problem? Of course using Namespaces. But, how do we define namespaces in Python? The good news is that you don’t have to define a namespace, a module itself is treated as a namespace by default in Python. But, there is a way which is also a standard and safe practice amongst python developers. i.e. using import <module>
3. Using import <module> (Good Way)
Now, let’s re-write our code using import <module>
# myModule.py import module1 import module2 print(module1.getName()) #This will print 'First Module' print(module2.getName()) #This will print 'Second Module'
This is how Namespaces are used in Python. When we say import <module> python interpreter only stores the methods and variables in memory with namespace module . So, after importing the module the user will not be able to just call getName() directly, he/she will have to mention the module from which the getName() method needs to be called. For example module1.getName() (for C/C++ developers it is same as myNamespace::myMethod() )
Namespaces for packages in Python: The principle of Namespaces remains same while using a Package as well. For example,
# myModule.py import package1 import package2 str1 = package1.module1.getName() # Get Name from module module1.py from package package1 str2 = package1.module2.getName() # Get Name from module module2.py from package package1 str3 = package2.module1.getName() # Get Name from module module1.py from package package2 str4 = package2.module2.getName() # Get Name from module module2.py from package package2
This concludes the Namespaces in Python. If you have any questions, suggestions or recommendations please do let me know in comments section.