An object is a collection of data(attributes) and  behaviors(methods). A class, on the other hand, is a blueprint  that defines the attributes and methods that objects built from the class will possess.

You have already encountered and used objects and classes whether knowingly or unknowingly. The most obvious example of objects in python are the builtin data types.  For example, the builtin int class is used to represent integers, this means that any integer such as 1, 2, 3, -10, etc, is an instance/object of the int class.

print(type(9))
print(type(-100))

The builtin type  function returns the class that the input object is an instance of.

Similarly, all the other data types  have their own associated classes  that define how they  can be used and manipulated. 

print(type('Python'))
print(type([1, 2, 3, 4]))
print(type({1: 'one', 2: 'two'}))
print(type({1, 2, 3}))

Note:   A class acts as a prototype or a sketch for creating objects. It defines the structure of the objects, but does not create any object until an instance of the class is created.

This allows the same class to be used as template for multiple objects. For example we have multiple integers like  1, 2, 3, 4, 5, but they all share a common class - the int class.

We now know  that a class is a blueprint or template for creating objects while objects are individual instantiations of the class that contain all the properties and behaviors defined in the class.  In the next part we will learn how classes are defined as well as how objects are created from the classes. 

Defining classes

In Python, classes are constructed using the class keyword.  The following example demonstrates the simplest class.

#This is a class
class MyClass:
   pass

The class definition starts with the class keyword followed by a name (of our choice) identifying the class, and is terminated with a colon. 

class ClassName:
   #class body goes here

Note: The class name should follow the standard variable naming rules (it must start with a letter or underscore, and can only be comprised of letters, underscores, or numbers).

It is  a convention to define class names with  CamelCase. CamelCase is where each word in the name begins with a capital letter (e.g. MyClassName). This convention makes it easier  to identify classes in the source code.

Creating objects from classes

We now have the simplest class we can have in Python, and as we said classes are simply blueprints. So how can we create objects from the blueprint?

To create objects from a class, we simply type the class name followed by a pair of parentheses. Just like how we call functions.

#define the class
class MyClass:
   pass

#create an object from the class
myclass_object = MyClass()
print(myclass_object)

#create another object
another_object = MyClass()
print(another_object)

Adding attributes

Objects are just entities made of attributes and methods.  Our previous example class is fairy useless in that it doesn't have any properties or methods defined for its objects.

In this part we will learn how we create objects that have data associated with them. Let us consider a class named, Point as in a point in a Cartesian plane . For a point to be valid  It must have two properties : x- coordinate and  y - coordinate.

#Define the class
class Point:
    x = 0
    y = 0

#Create objects of the class 
p1 = Point()
p2 = Point()
p3 = Point()

#Override the value of attributes through assignment
p2.x = 1
p2.y = 3

p3.x = 4
p3.y = 6

print(p1.x, p1.y, sep = ' ')
print(p2.x, p2.y, sep = ' ')
print(p3.x, p3.y, sep = ' ')

The above class, Point, defines the attributes and . Each object that is created from this class automatically inherits those two attributes. The objects can then override those points with unique values through assignment as in the case of p2 and p3

Note: We access object's  attributes using the dot notation as shown above. i.e my_object.attribute 

Add Methods

Methods  are behavior associated with a class and its objects. The syntax of a method is just similar to that of a function.  I know you are already familiar with function definition and usage.

let us define a method for the Point class called reset() that resets the point of a Point object back to (0, 0).

#define the class
class Point:
   x = 0
   y = 0

   #define the reset method
   def reset(self):
       self.x = 0.0
       self. y = 0.0

#create an object
p = Point()

#assign new values to the x and y attributes
p.x = 10
p.y = 15

print(p.x, p.y, sep = ' ')

#reset the values
p.reset()

print(p.x, p.y, sep = ' ')

Let us define one more method called get_values  that returns the value of x and y from the Point object as a tuple i.e (x, y)

#define the class
class Point:
   x = 0
   y = 0

   #define the reset method
   def reset(self):
       self.x = 0.0
       self. y = 0.0
   def get_values(self):
       return (self.x, self.y)

#create an object
p = Point()

#assign new values to the x and y attributes
p.x = 10
p.y = 15

print(p.get_values())

#reset the values
p.reset()

print(p.get_values())

Note: A method is formatted identically to a function. It starts with the keyword def followed by a space and the name of the method. This is followed by a set of parentheses containing the parameter list and then it is  terminated with a colon.

The next line after the definition is indented to contain the method's body. 

we'll discuss that  special parameter,  self , in just a moment.

Objects referencing themselves

The self argument that you've just seen above is  a special one in that it refers to the current instance of the class.

When we  are assigning values outside a class,  we use normal assignment.

#define a class 
class Point():
    x = 0
    y = 0

p = Point()
p. x = 10
p.y = 7

print(p.x, p.y, sep = ' ')

The self argument helps us achieve similar functionality when defining the class. 

class Point:
   def some_method(self):
        self.x = 10
        self.y = 7

p = Point()
p.some_method()

print(p.x, p.y, sep = ' ')

Normally, the first argument of any function defined inside a class will reference the current instance of the class(unless we explicitly override this behavior using some special decorators).

"self" is the most conventionally used name for the first argument of instance methods . It is similar to "this" in other languages such as c++.

Consider the following example.

class Point:
    x = 0
    y = 0
    def reset():
       x = 0
       y = 0

p = Point()
p.reset()

An error is raised indicating that an argument was passed to the some_method function. This is because, in the background, Python tried to pass instance p to the some_method function and the function does not take any arguments. 

Whenever defining an instance method, never forget to use self as the first parameter, even if the method takes no arguments. An error will be raised if the method does not accept the extra argument self

Methods can take other arguments alongside 'self'

Like normal function, methods can specify the arguments that should be passed to it when being called . But we now know that the first parameter of any method should be self.

Consider our example of the class Point, we can define a method called update which will take two arguments, x and y  and then update the existing points with the given values.

#define the class
class Point:
   x = 0
   y = 0
   #define the update method
   def update(self, x, y):
       self.x = x
       self.y = y

p = Point()
print(p.x, p.y, sep = ' ')

#Update the value of x and y for object p
p.update(7, 12)
print(p.x, p.y)

Note: The argument self is passed to the methods by Python in the background. We only have to pass  the additional arguments when calling the a method.

In the next part we will look at class constructors.

Summary

  1. A class is just a prototype for its objects.
  2. An objects is an individual instance of the given class
  3. Classes are defined with the class keyword, followed by the name of the class.
  4. Objects are created using the class name, followed by parentheses containing any arguments needed by the __init__() method.
  5. Attributes define an object of a class.
  6. Methods perform actions that are relevant to the given object.
  7. We access attributes and methods of an object using the dot notation.
  8. The self parameter refers to the instance of the class, and is always required when defining methods in a class.