Class methods are methods that receive the class itself as the first argument (conventionally `cls`) and are defined using the `@classmethod` decorator. They can modify class state. Static methods do not receive an implicit first argument and are defined using the `@staticmethod` decorator; they behave like regular functions but belong to the class's namespace.
The four pillars are Encapsulation (bundling data and methods), Abstraction (hiding complex implementation details), Inheritance (deriving new classes from existing ones), and Polymorphism (using a unified interface for different data types).
The `super()` function returns a temporary object of the superclass, allowing access to its methods. It is commonly used to call the superclass's `__init__` method in the subclass to ensure proper initialization.
Inheritance is implemented by defining a class that inherits from a parent class. For example, `class ChildClass(ParentClass):` allows `ChildClass` to inherit attributes and methods from `ParentClass`, promoting code reuse and hierarchical relationships.
Polymorphism allows objects of different classes to be treated as instances of a common superclass, typically using methods with the same name but different implementations. For example, different classes like `Dog` and `Cat` can both have a `speak()` method, which behaves differently depending on the object's class.
Encapsulation is the bundling of data and methods within a class, restricting direct access to some components. In Python, it is achieved using private (prefixing with double underscores `__`) and protected (prefixing with a single underscore `_`) attributes, signaling that they should not be accessed directly outside the class.
Python allows a class to inherit from multiple parent classes by listing them in parentheses. For example, `class Child(Parent1, Parent2):` enables the child class to inherit attributes and methods from both `Parent1` and `Parent2`. Python uses the Method Resolution Order (MRO) to determine the order in which base classes are searched.
Method overriding occurs when a subclass provides a specific implementation of a method that is already defined in its superclass. This allows the subclass to modify or extend the behavior of that method.
You can prevent a class from being subclassed by using the `final` decorator from the `typing` module (in Python 3.8+) or by raising an exception in the `__init_subclass__` method. For example:
```python
from typing import final
@final
class Base:
pass
```
This will cause an error if someone tries to inherit from `Base`.
Abstraction is implemented using abstract base classes (ABCs) from the `abc` module. By defining abstract methods using the `@abstractmethod` decorator, you can create classes that cannot be instantiated and must have their abstract methods overridden in subclasses. This enforces a common interface.