Encapsulation:Python classes are designed to encapsulated related data and bahavior into a single unit.
Inheritance:Python supports inheritance, which allows classes to inherit attributes and methods from parent classes. This makes it easier to reuse code and create hierarchies of related classes.
Polymorphism:Python supports polymorphism, which means that objects of different classes can be treated as if they are the same type. This allows for greater flexibility in the design of your code.
Composition:Python encourages the use of composition over inheritance, which means that objects are made up of other objects rather than being derived from parent classes. This can make your code more modular and easier to maintain.
Duck typing: Python uses duck typing, which means that the type of an object is determined by its behavior rather than its class. This makes it easier to write generic code that works with a variety of objects.
Special methods: Python has a number of special methods that allow you to define custom behavior for built-in operations. For example, the __len__ method allows you to define how the len() function works with objects of your class.
Readability: As with the general design principles of Python, classes should also prioritize readability and simplicity. This means using clear and concise names for methods and attributes, avoiding unnecessary complexity, and following PEP 8 guidelines for formatting.
Special methods
Special methods in Python are a set of predefined methods that allow you to define custom behavior for built-in operations on your objects. They are identified by their double underscore prefix and suffix, also known as "dunder" methods.
Here are some of the most commonly used special methods in Python:
<ol>__init__(self, ...): This is the constructor method that is called when an object is called. It initializes the object's attributes and sets its initial state.
__str__(self): This methods returns a string representation of the object. It's called by the str() function and by the print() statement.
__repr__(self): This method returns a string representation of the object that can be used to recreate the object. It is called by the repr() function and by the interactive Python shell. The difference between __str__ and __repr__ is that __repr__ is used to create an unambiguous string representation of an object that can be used to recreate the object, while __str__ is used to create a human-readable string representation of an object.
__len__(self): This method returns the length of the object. It is called by the len() function.
__getitem__(self, key): This method allows you to access an item in the object using bracket notation. It is called when you use the bracket operation([]) on the object.
__setitem__(self, key, value): This method allows you to set the value of an item in the object using bracket notation. It is called when you use the bracket operation([]) on the object with an assignment.
__delitem__(self, key): This method allows you to delete an item from the object using bracket notation. It is called when you use the del statement on the object with bracket notation.
__add__(self, other): This method allows you to define how the + operator works with your object. It is called when you use the + operator on the object.
__eq__(self, other): This method allows you to define how the == operator works with your object. It is called when you use the == operator on the object.
__lt__(self, other): This method allows you to define how the