It is important to understand the difference between class and instance. To do so, we must familiarize ourselves to concept of namespace.
Namespace
declarative region that provides a scope to the identifiers (the names of types, functions, variables, etc) inside it
For example, when a = 2, variable a possesses the address of the object where 2 is stored - and this declarative region is namespace.
To see how namespace works in Python, we will first create class Bands
Input
class Bands:
england = 'The Rolling Stones'
After creating the class, we will use Python's dir() method to return the list of names in the current local scope.
Input
dir()
Output
['Bands', '__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']
We now see that the class Bands is inside the local scope.
Input
Bands()
Output
<__main__.Bands at 0x7ff66e981e10>
Input
Bands1()
Output
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-4-05e07d145e4f> in <module>
----> 1 Bands1()
NameError: name 'Bands1' is not defined
When class is defined in Python, independent namespace is created within the scope. Moreover, variables or methods defined within the class are stored in namespace as Python dictionary type.
To check the namespace of class Bands we can use the dict method.
Input
Bands.__dict__
Output
mappingproxy({'__module__': '__main__',
'england': 'The Rolling Stones',
'__dict__': <attribute '__dict__' of 'Bands' objects>,
'__weakref__': <attribute '__weakref__' of 'Bands' objects>,
'__doc__': None})
We see {'england' : 'The Rolling Stones'} inside the class namespace.
Since the class has its own namespace with independent variable and method, we can easily access it from what we have learned from the previous posts.
Input
Bands.england
Output
'The Rolling Stones'
Now, we will make two different instances.
Input
b1 = Bands()
b2 = Bands()
print('b1 ID : ', id(b1))
print('b2 ID : ', id(b2))
Output
b1 ID : 140696391664528
b2 ID : 140696391665040
In Python, instances also possess their own namespaces.
First, we will check whether or not the namespaces have been succesfully created for each instances. And then check namespace of each instance b1 and b2
Input
dir()
Output
['Bands', '__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'b1', 'b2']
Input
b1.__dict__
Output
{}
Input
b2.__dict__
Output
{}
We see that b1 and b2 have empty namepsaces. We will now add variable 'england' to b1.
Input
b1.england = 'The Queen'
b1.__dict__
Output
{'england': 'The Queen'}
However, since we did not assign any new value to b2, namespace of b2 is yet empty.
Input
b2.__dict__
Output
{}
Right now, we have two instance b1 and b2. Although instance b1 has variable england, b2 does not have any value assigned to it. What happens if we access .england using two different instances?
Input
b1.england
Output
'The Queen'
Input
b2.england
Output
'The Rolling Stones'
Although we have not assigned any value to b2, the instance returns 'The Rolling Stones'. This is because Python first finds whether or not value exists in instance s2 and if not access to the class of s2 and finds for the same variable in class's namespace.
However, what would happen if we look for the name of non-English bands in the class? Perhaps for an American band?
Input
b2.america
Output
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-36-33d5f616d215> in <module>
----> 1 b2.america
AttributeError: 'Bands' object has no attribute 'america'
Since america is neither in instance b2 nor class Bands, error is returned.