Instance variables: for data which is unique to every object
Class variables: for data shared between different instances of a class
Let’s take a look at an example:
classCal(object):# pi is a class variable pi =3.142def__init__(self,radius):# self.radius is an instance variableself.radius = radiusdefarea(self):returnself.pi *(self.radius **2)a =Cal(32)a.area()# Output: 3217.408a.pi# Output: 3.142a.pi =43a.pi# Output: 43b =Cal(44)b.area()# Output: 6082.912b.pi# Output: 3.142b.pi =50b.pi# Output: 50
There are not many issues while using immutable class variables. This is the major reason due to which beginners do not try to learn more about this subject because everything works! If you also believe that instance and class variables can not cause any problem if used incorrectly then check the next example.
That is the beauty of the wrong usage of mutable class variables. To make your code safe against this kind of surprise attacks then make sure that you do not use mutable class variables. You may use them only if you know what you are doing.
New style classes
Old base classes do not inherit from anything
New style base classes inherit from object
Example:
Inheritance from object allows new style classes to utilize some magic:
Optimizations like __slots__.
super() and descriptors and the likes
Bottom line? Always try to use new-style classes!
Note:Python 3 only has new-style classes. It does not matter whether you subclass from objector not. However it is recommended that you still subclass from object.
Magic Methods (dunder)
Magic methods, commonly called dunder (double underscore) methods.
__init__
It is a class initializer.
Whenever an instance of a class is created its __init__ method is called.
Example:
__init__ is called immediately after an instance is created.
You can pass arguments to the class during it’s initialization:
__getitem__
Implementing getitem in a class allows its instances to use the [] (indexer) operator.
Example:
Without the __getitem__ method we would get this error:
class OldClass():
def __init__(self):
print('I am an old class')
class NewClass(object):
def __init__(self):
print('I am a jazzy new class')
old = OldClass()
# Output: I am an old class
new = NewClass()
# Output: I am a jazzy new class
class GetTest(object):
def __init__(self):
print('Greetings!!')
def another_method(self):
print('I am another method which is not'
' automatically called')
a = GetTest()
# Output: Greetings!!
a.another_method()
# Output: I am another method which is not automatically
# called
class GetTest(object):
def __init__(self, name):
print('Greetings!! {0}'.format(name))
def another_method(self):
print('I am another method which is not'
' automatically called')
a = GetTest('yasoob')
# Output: Greetings!! yasoob
# Try creating an instance without the name arguments
b = GetTest()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __init__() takes exactly 2 arguments (1 given)