Python Classes & Objects¶
Info
Classes are blueprints for objects. Objects are instances of classes. Classes can be used to create multiple objects.
class Car:
def __init__(self, color, model):
self.color = color
self.model = model
def drive(self):
print("Driving a", self.color, self.model)
ferrari = Car("red", "Ferrari")
audi = Car("blue", "Audi")
ferrari.drive()
audi.drive()
# Output:
# >>> Driving a red Ferrari
# >>> Driving a blue Audi
Important to know:
self
is a reference to the current instance of the classself
comes always first in the method definition__init__
is the constructor of the class (see more here)__init__
is called when an object is created (after__new__
)- All classes inherit from
object
by default
Arguments¶
Optional Arguments¶
Info
Optional arguments can be used to set default values for attributes.
class Car:
def __init__(self, color, model, battery=0):
self.color = color
self.model = model
self.battery = battery
def drive(self):
print("Driving a", self.color, self.model, "with", self.battery, "kWh")
car = Car("red", "Ferrari")
e_car = Car("green", "Tesla", 100)
car.drive()
e_car.drive()
# Output:
# >>> Driving a red Ferrari with 0 kWh
# >>> Driving a green Tesla with 100 kWh
Positional Arguments¶
Info
Positional arguments can be used to set attributes in the order they are defined in the class.
class Car:
def __init__(self, color, model):
self.color = color
self.model = model
def drive(self):
print("Driving a", self.color, self.model)
car = Car("red", "Ferrari")
car.drive()
# Output:
# >>> Driving a red Ferrari with 0 kWh
Keyword Arguments¶
Info
Keyword arguments can be used to set attributes in any order accessible by their keyname.
class Car:
def __init__(self, color, model):
self.color = color
self.model = model
def drive(self):
print("Driving a", self.color, self.model)
car = Car(model="Ferrari", color="red")
car.drive()
# Output:
# >>> Driving a red Ferrari with 0 kWh
*args
& **kwargs
¶
Info
*args
and **kwargs
can be used to pass a variable number of arguments to a function like a list or a dictionary.
*args
is used to pass a variable number of positional arguments (arguments without a keyname)**kwargs
is used to pass a variable number of keyword arguments (arguments with a keyname)
def print_args_and_kwargs(*args, **kwargs):
for arg in args:
print(arg)
for key, value in kwargs.items():
print(key, value)
print_args_and_kwargs("Hello", "World", name="John", age=42)
# Output:
# >>> Hello
# >>> World
# >>> name John
# >>> age 42
Attributes¶
Object Attributes¶
Info
Object attributes are attributes that are defined in the __init__
method. They are unique for each instance of the class.
class Car:
def __init__(self, color, model):
self.color = color
self.model = model
def drive(self):
print("Driving a", self.color, self.model)
car = Car("red", "Ferrari")
print(car.color)
print(car.model)
# Output:
# >>> red
# >>> Ferrari
Class Attributes¶
Info
Class attributes are attributes that are defined outside of the __init__
method. They are shared between all instances of the class.
class Car:
total_cars = 0
def __init__(self, color, model):
self.color = color
self.model = model
Car.total_cars += 1
def drive(self):
print("Driving a", self.color, self.model)
car1 = Car("red", "Ferrari")
car2 = Car("blue", "Ferrari")
print(Car.total_cars)
# Output:
# >>> 2
Semi-Private Attributes¶
Info
Semi-private attributes are attributes that are defined with a single underscore _
in front of the attribute name. They can be accessed from outside the class but should not be accessed. This is just a convention for developers to know that these attributes are for internal use only.
class Car:
def __init__(self, color, model, secret):
self.model = model
self.color = color
self._secret = secret
def get_secret(self):
return self._secret
def set_secret(self, secret):
self._secret = secret
car = Car("blue", "Ferrari", "secret")
print(car.get_secret())
print(car._secret)
# Output:
# >>> secret
# >>> secret
Private Attributes¶
Info
Private attributes are attributes that are defined with a double underscore __
in front of the attribute name. They can only be accessed from within the class. This is used to prevent accidental access from outside the class.
class Car:
def __init__(self, color, model, secret):
self.model = model
self.color = color
self.__secret = secret
def get_secret(self):
return self.__secret
def set_secret(self, secret):
self.__secret = secret
car = Car("blue", "Ferrari", "secret")
print(car.get_secret())
print(car.__secret)
# Output:
# >>> secret
# >>> AttributeError: 'Car' object has no attribute '__secret'
Property Attributes¶
Info
Property attributes are attributes that are defined with the @property
decorator. They are used to access private attributes from outside the class. By using the @property
decorator, the private attribute can be accessed like a normal attribute. By using the @attribute.setter
decorator, the private attribute can be modified like a normal attribute.
class Car:
def __init__(self, color, model, secret):
self.model = model
self.color = color
self.__secret = secret
@property
def secret(self):
return self.__secret
@secret.setter
def secret(self, value):
self.__secret = value
car = Car("blue", "Ferrari", "secret")
car.secret
car.secret = "new secret"
car.secret
# Output:
# >>> secret
# >>> new secret
Methods¶
__new__
¶
Info
The __new__
method is called before an object is created. It is used to modify the object during creation.
class Car:
def __new__(cls, color, model):
if color == "red":
return super().__new__(cls)
else:
return None
def __init__(self, color, model):
self.color = color
self.model = model
car = Car("red", "Ferrari")
car = Car("blue", "Ferrari")
print(car.color)
print(car)
# Output:
# >>> red
# >>> None
__init__
¶
Info
The __init__
method is called when an object is created. It is used to initialize the object's attributes and methods.
class Car:
def __init__(self, color, model):
self.color = color
self.model = model
car = Car("red", "Ferrari")
print(car.color)
# Output:
# >>> red
__str__
& __repr__
¶
Info
- The
__str__
method is called when the object is printed. It should return a string representation of the object. - The
__repr__
method is called when the object is printed in the console. It should return a string representation of the object.
class Car:
def __init__(self, color, model):
self.color = color
self.model = model
def __str__(self):
return "Car(color={}, model={})".format(self.color, self.model)
def __repr__(self):
return "Car(color={}, model={})".format(self.color, self.model)
car = Car("red", "Ferrari")
print(car) # This will call __str__
car # This will call __repr__
# Output:
# >>> Car(color=red, model=Ferrari)
# >>> Car(color=red, model=Ferrari)
@abstractmethod
¶
Info
The @abstractmethod
decorator is used to define abstract methods. Abstract methods are methods that are not implemented in the class but must be implemented in the subclass.
from abc import ABCMeta, abstractmethod
class Car(metaclass=ABCMeta):
def __init__(self, color, model):
self.color = color
self.model = model
@abstractmethod
def drive(self):
pass
class Ferrari(Car):
def drive(self):
print("Driving a", self.color, self.model)
car = Car("red", "Ferrari")
# Output:
# >>> TypeError: Can't instantiate abstract class Car with abstract methods drive
ferrari = Ferrari("red", "Ferrari")
ferrari.drive()
# Output:
# >>> Driving a red Ferrari
@staticmethod
¶
Info
The @staticmethod
decorator is used to define static methods. Static methods are methods that do not require an instance of the class to be called. They are usually used to create utility functions which are belonging to a class thematically.
class Car:
def __init__(self, color, model):
self.color = color
self.model = model
@staticmethod
def drive():
print("Driving a car")
car = Car("red", "Ferrari")
car.drive()
# Output:
# >>> Driving a car
@classmethod
¶
Info
The @classmethod
decorator is used to define class methods. Class methods are methods that are bound to the class and not to an instance of the class. They are usually used to create factory methods which are used to create an instance of the class.
class Car:
total_cars = 0
def __init__(self, color, model):
self.color = color
self.model = model
Car.total_cars += 1
@classmethod
def get_total_cars(cls):
return cls.total_cars
car1 = Car("red", "Ferrari")
car2 = Car("blue", "Ferrari")
print(Car.get_total_cars())
# Output:
# >>> 2
Concepts¶
The following concepts are important to understand object-oriented programming. They are not specific to Python. They are also used in other oop languages like Java.
Abstraction¶
Info
Abstraction means that only the relevant information is shown to the user. The user does not need to know the internal details of the object.
class Car:
def __init__(self, color, model, key):
self.color = color
self.model = model
self.__key = key
def drive(self):
if self.__key == True:
print("Driving a", self.color, self.model)
else:
print("You need the correct key to drive this car")
def get_key(self):
return self.__key
def set_key(self, key):
self.__key = key
car = Car("red", "Ferrari", True)
car.drive()
car.set_key(False)
car.drive()
# Output:
# >>> Driving a red Ferrari
# >>> You need the correct key to drive this car
Encapsulation¶
Info
Encapsulation means that the internal representation of an object is hidden from the outside. Only the object itself can access and modify its internal state.
class Car:
def __init__(self, color, model):
self.__color = color
self.__model = model
def drive(self):
print("Driving a", self.__color, self.__model)
def get_color(self):
return self.__color
def set_color(self, color):
self.__color = color
car = Car("yellow", "VW")
car.drive()
car.set_color("orange")
car.drive()
# Output:
# >>> Driving a yellow VW
# >>> Driving a orange VW
Inheritance¶
Info
Classes can inherit from other classes. The child class inherits all attributes and methods from the parent class.
Warning
Methods and attributes can be overwritten in the child class. The parent class is not affected.
class ElectricCar(Car):
def __init__(self, color, model, battery):
super().__init__(color, model)
self.battery = battery
def charge(self):
print("Charging", self.color, self.model, "with", self.battery, "kWh")
car = ElectricCar("green", "Tesla", 100)
car.drive()
# Output:
# >>> Driving a green Tesla with 100 kWh
Polymorphism¶
Info
Polymorphism means that the same method can be used for different types of objects. The method will behave differently depending on the type of object.
class Car:
def __init__(self, color, model):
self.color = color
self.model = model
def drive(self):
print("Driving a", self.color, self.model)
class ElectricCar(Car):
def __init__(self, color, model, battery):
super().__init__(color, model)
self.battery = battery
def drive(self):
print("Driving a", self.color, self.model, "with", self.battery, "kWh")
car = Car("red", "Ferrari")
e_car = ElectricCar("green", "Tesla", 100)
car.drive()
e_car.drive()
# Output:
# >>> Driving a red Ferrari
# >>> Driving a green Tesla with 100 kWh