Namespaces provide a way for managing identifiers defined within a scope. In other words, they are used to map names to values (or references to the memory location to be more precise).
For example, in the context of a namespace the following expression
x = 10
will associate identifier x
to the memory location that holds object with value 10
.
In Python, there are essentially two "types" of namespaces; instance and class namespaces.
Instance Namespace manages the mapping between names and values within the scope of a individual object. On the other hand, there is a separate Class Namespace for every class defined in the source code. This type of namespace handles all the members which are shared by all instances of the object.
Example
Now consider the following example where for each member it is denoted whether it belongs to a class or instance namespace:
class Customer:
def __init__(self, first_name, last_name, email): # __init__ -> Customer Class Namespace
self._first_name = first_name # _first_name -> Instance Namespace
self._last_name = last_name # _last_name -> Instance Namespace
self._email = email # _email -> Instance Namespace
def get_full_name(self): # Customer Class Namespace
return f"{self._first_name} {self._last_name}"
class PremiumCustomer(Customer):
PREMIUM_MEMBERSHIP_COST = 4.99 # PremiumCustomer Class Namespace
class Subscription: # PremiumCustomer Class Namespace
def __init__(self, customer_email): # Subscription Class Namespace
self._customer_email = customer_email # Instance Namespace
def __init__(self, first_name, last_name, email, card_number): # PremiumCustomer Class Namespace
super().__init__(first_name, last_name, email)
self._card_number = card_number # _card_number -> Instance Namespace
def get_card_number(self): # PremiumCustomer Class Namespace
return self._card_number