1. Home
  2. Docs
  3. Object Oriented Programming in Python
  4. Attributes Continued – Instance attributes

Attributes Continued – Instance attributes

Instance Attributes

In the last lesson you learnt about creating class, and instances.

And adding attributes to class

In this section we continue to explore attributes,

with respect to classes and instances attributes.

Like classes, instances can also have their own attributes.

And you can add attributes at any time by using dot notation.

Lets add attribute ‘a’ and ‘b’ to obj_1 and obj_2

#creating obj_1 object

obj_1 = MyClass()

#creating obj_2 object

obj_2 = MyClass()

#setting a,b attributes of obj_1

obj_1.a  = 15

obj_1.b = 20

#setting a,b attributes of obj_2

obj_2.a = 25

obj_2.b = 30

#check the values

print(obj_1.a, obj_1.b)

print(obj_2.a, obj_2.b)


Output:

15 20

25 30


Notice the obj_1 and obj_2 attributes have different set of values.

Here we have defined instance attributes outside the class body.

Here ‘a’ and ‘b’ are attributes of objects, not class.

Object specific properties are called, instance attributes.

Usually instance attributes are defined instance methods,

in the next lesson you learn about instance methods.

 

Let’s take another example of Employee class.

 

Example:
 
An employee has first name and last name as instance attributes.

  


class Employee(object):
    pass


#Create an object 

emp_1 = Employee() # first employee instance

#Create an object 

emp_2 = Employee() # second employee instance


#add first_name and last_name attribute 

emp_1.first_name = "James" 

emp_1.last_name = "Tylor" 


#add first_name and last_name attribute 

emp_2.first_name = "Anne" 

emp_2.last_name = "Holmes"


# emp_2 has an extra attribute email



emp_2.email = emp_2.first_name + "." + emp_2.last_name +"@company.com"


print("emp_1 full name : ",emp_1.first_name, emp_1.last_name) 

print("emp_2 full name : ",emp_2.first_name, emp_2.last_name)

print("emp_2 email : ", emp_2.email)


Output:

emp_1 full name :  James Tylor

emp_2 full name :  Anne Holmes

emp_2 email :  [email protected]

  
Please note emp_2 has an extra attribute, email.

emp_1 don’t have this attribute.

if you try to access email property with emp_1.
  

print("emp_1 email : ", emp_1.email)

  
you get an attribute error.
  

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-28-3fa303d90e1b> in <module>()
----> 1 print("emp_1 email : ", emp_1.email)

AttributeError: 'Employee' object has no attribute 'email'

  

Now we have only two employee details.

But imagine if you have to add first name and last name of hundreds of  employees.

and You need to add these instance attributes to each object,

which is lot of work and redundant.

To solve this we have methods.

Specially the __init__ () method.

Think this method as initializer of the object.

For people who already now other OOP languages, its similar to constructor.

But in Python __init__() just initializes objects after the object is constructed.

Another special methods __new__() constructs the object,

which takes only one argument, that is class name.

 

Let’s continue with our Employee class, with a __init__() special method.

We  supply  necessary attribute values to __init__ method,

as arguments, which have to be applied to object.

In this case first_name, last_name.
  

class Employee(object):

    def __init__(self, first_name, last_name):

        self.first_name = first_name

        self.last_name = last_name



# Object created with attributes
        
emp_1 = Employee("James","Tylor") 
    
emp_2 = Employee("Anne","Holmes")  
   
emp_3 = Employee("John","Max")   
     
emp_4 = Employee("Claira","Turner")

print(emp_1.first_name, emp_1.last_name)

print(emp_2.first_name, emp_2.last_name)

print(emp_3.first_name, emp_3.last_name)

print(emp_4.first_name, emp_4.last_name)



output:

James Tylor

Anne Holmes

John Max

Claira Turner

  

__init__() Method:

 

The __init__(), is a special method,

its starts and ends with double underscores.
  

def __init__(self, first_name, last_name):

  
Such methods are called dunder methods or magic methods.

dunder refers to the double underscores at the start and end of function name.
  

Why these are called magic methods?

 
The magic is, you don’t have to invoke these functions explicitly.

They are invoked by Python interpreter automatically.

We will cover more about magic methods later section.

 

Coming back to __init__ method.
 

This is an initializer method, self is the first argument,

its a reference of the object on which method is applied.

While defining instance methods, you have pass this as first argument explicitly.

But when these methods are called,

Python automatically passes self parameter to called method.

  

What is the difference between class attribute and instance attribute ?

 

Class attribute

 
Class attribute are shared across instances,

and are accessed by all instances of that class.

There is only one copy of the class attribute.

If any one object modifies its value, the change is seen in all other instances.

class attributes are accessed with ClassName.attribute dot notation.
 

Instance attributes

 
Instance attributes are owned by individual instances.

They are not shared among instances, and each instance has its own copy of the attribute.

If instance attribute is modified, its only reflected to that instance, not to other instances of the class.

Instance attributes are accessed with self.attribute dot notation.

To understand this lets consider an example.
.

Below we have MyClass, it has class attribute x,

two special methods __init__ and __del__

We also have static method count(), to print the class attribute.

  

class MyClass(object):

    x = 0

    def __init__(self):

        MyClass.x += 1

    def __del__(self):
        MyClass.x -= 1


    def count():

        print(MyClass.x)


m1 = MyClass()


MyClass.count()

m2 = MyClass()



MyClass.count()


print("Destroy m1 and m2.")

del m1

MyClass.count()

del m2

MyClass.count()

output:

1
2
Destroy m1 and m2.
1
0

  
Note inside __init__ we are accessing the class variable by prefixing class name

MyClass.x += 1

Now the same example with instance variable
  


class MyClass(object):

    x = 0

    def __init__(self):

        self.x += 1

    def __del__(self):
        self.x -= 1


    def count():

        print(MyClass.x)

    #count = staticmethod(count)
   



m1 = MyClass()


MyClass.count()

m2 = MyClass()



MyClass.count()


print("Destroy m1 and m2.")

del m1

MyClass.count()

del m2

MyClass.count()

output:

0
0
Destroy m1 and m2.
0
0


  

Note inside __init__ x becomes an instance attribute,

and it doesn’t affect the class or other instance attribute.

  

In the next section we will explore class and instance methods.