What is Name in Python Programming?
A namespace is a system to have a unique name for each and every object in Python. An object might be a variable or a method. Python itself maintains a namespace in the form of a Python dictionary. Namespaces are one honking great idea -- let's do more of those!
Name (also called identifier) is simply a name given to objects. Everything in A python is an object. Name is a way to access the underlying object.
For example, when we do the assignment a = 2, here 2 is an object stored in memory and a is the name we associate it with. We can get the address (in RAM) of some object through the built in function, id(). Let's check it.
# Note: You may get different value of id
a = 2
# Output: id(2)= 10919424
print('id(2) =', id(2))
# Output: id(a) = 10919424
print('id(a) =', id(a))
Here, both refer to the same object. Let's make things a little more interesting.
# Note: You may get different value of id
a = 2
# Output: id(a) = 10919424
print('id(a) =', id(a))
a = a+1
# Output: id(a) = 10919456
print('id(a) =', id(a))
# Output: id(3) = 10919456
print('id(3) =', id(3))
b = 2
# Output: id(2)= 10919424
print('id(2) =', id(2))
What is happening in the above sequence of steps? A diagram will help us explain this.
Initially, an object 2 is created and the name a is associated with it, when we do a = a+1, a new object 3 is created and now associates with this object.
Note that id(a) and id(3) have the same values.
Furthermore, when we do b = 2, the new name b gets associated with the previous object 2.
This is efficient as Python doesn't have to create a new duplicate object. This dynamic nature of name binding makes Python powerful; a name could refer to any type of object.
>>> a = 5
>>> a = 'Hello World!'
>>> a = [1,2,3]
All these are valid and a will refer to three different types of object at different instances. Functions are objects too, so a name can refer to them as well.
def printHello():
print("Hello")
a = printHello()
# Output: Hello
a
Our same name a can refer to a function and we can call the function through it, pretty neat.
What is a Namespace in Python Programming?
So now that we understand what names are, we can move on to the concept of namespaces.
To simply put, the namespace is a collection of names.
In Python, you can imagine a namespace as a mapping of every name, you have defined, to corresponding objects.
Different namespaces can co-exist at a given time but are completely isolated.
A namespace containing all the built-in names is created when we start the Python interpreter and exists as long we don't exit.
This is the reason that built-in functions like id(), print(), etc. are always available to us from any part of the program. Each module creates its own global namespace.
These different namespaces are isolated. Hence, the same name that may exist in different modules does not collide.
Modules can have various functions and classes. A local namespace is created when a function is called, which has all the names defined in it. Similar is the case with class. The following diagram may help to clarify this concept.
Python Programming Scope
Scope refers to the coding region from which a particular Python object is accessible. Hence one cannot access any particular object from anywhere from the code, the accessing has to be allowed by the scope of the object.
At any given moment, there are at least three nested scopes.
- the innermost scope is searched first and it contains the local names
- the scopes of any enclosing functions, which are searched starting with the nearest enclosing scope
- the next-to-last scope contains the current module's global names
- the outermost scope, which is searched last, is the namespace containing the built-in names
When a reference is made inside a function, the name is searched in the local namespace, then in the global namespace and finally in the built-in namespace.
If there is a function inside another function, a new scope is nested inside the local scope.
Example of Scope and Namespace in Python
As can be seen in the above output the function some_func() is in the scope from main but var is not avaialable in the scope of main. Similarly, in the case of inner functions, outer functions don’t have the accessibility of inner local variables which are local to inner functions and out of scope for outer functions.
In the next example, we’ll see the list of names inside some nested functions. The code in this block continues from the previous block.
def outer_foo():
outer_var = 3
def inner_foo():
inner_var = 5
print(dir(), ' - names in inner_foo')
outer_var = 7
inner_foo()
print(dir(), ' - names in outer_foo')
outer_foo()
The output is as follows.
['inner_foo', 'outer_var'] - names in outer_foo