In Python, we have the ability to define our own classes to create custom objects. These objects are instances of a class, and a class represents the type of an object.

To define a class, we use the following syntax:

class ClassName:
    # class definition

For example, let’s define a Dog class:

class Dog:
    # the Dog class

Inside a class, we can define methods, which are functions associated with the class. For example, let’s add a bark() method to the Dog class:

class Dog:
    # the Dog class
    def bark(self):
        print('WOF!')

In this case, self is the argument that refers to the current object instance and must be included in the method definition.

To create an instance of a class (an object), we use the following syntax:

roger = Dog()

Now, roger is an object of type Dog. We can check the object’s type using the type() function:

print(type(roger))  # <class '__main__.Dog'>

In addition to regular methods, there is a special method called __init__(), which is known as the constructor. This method allows us to initialize properties when creating a new object. For example:

class Dog:
    # the Dog class
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def bark(self):
        print('WOF!')

We can create a Dog object and access its properties and methods like this:

roger = Dog('Roger', 8)
print(roger.name)  # 'Roger'
print(roger.age)  # 8

roger.bark()  # 'WOF!'

One important feature of classes is inheritance. We can create a parent class, such as an Animal class, with its own methods. Then, other classes, like the Dog class, can inherit these methods:

class Animal:
    def walk(self):
        print('Walking..')

class Dog(Animal):
    def bark(self):
        print('WOF!')

Now, objects of the Dog class will have both the bark() method from the Dog class and the walk() method inherited from the Animal class:

roger = Dog()
roger.walk()  # 'Walking..'
roger.bark()  # 'WOF!'

By defining classes, we can create custom objects with their own properties and behaviors, and even reuse methods from other classes through inheritance.