Tasks studies - laboratory
Previously, we analyzed two programming paradigms:
Another very popular paradigm is Object-Oriented Programming (OOP).
Objects are created using classes, which are actually the central point of OOP.
A class describes what an object will be but is separate from the object itself.
In other words, a class can be thought of as a blueprint, description, or definition of an object.
You can use the same class as a plan to create multiple different objects.
Classes are created using the class keyword and indented blocks containing class methods (which are functions).
Below is an example of a simple class and its objects:
class Cat:
def __init__(self, color, legs):
self.color = color
self.legs = legs
felix = Cat("ginger", 4)
rover = Cat("dog-colored", 4)
stumpy = Cat("brown", 3)
print(felix.color)
This code defines a class called
Cat, which has two attributes: color and legs.
The class is then used to create three separate objects (instances of the class).
__init__ MethodThe __init__ method is the most important method in a class.
It is called when an instance (object) of the class is created using the class name as a function.
self as the first parameter, although it is not explicitly passed when calling the method.self argument—you do not need to include it when calling a method.self parameter refers to the instance calling the method.Class instances have attributes, which are data associated with them.
In this example, Cat instances have color and legs attributes.
You can access them using dot notation: instance.attribute.
class Cat:
def __init__(self, color, legs):
self.color = color
self.legs = legs
felix = Cat("ginger", 4)
print(felix.color)
The
__init__method is the constructor of the class.
Classes can have other methods to add functionality.
All methods must have self as the first parameter.
Methods are accessed using dot notation, just like attributes.
class Dog:
def __init__(self, name, color):
self.name = name
self.color = color
def bark(self):
print("Woof!")
fido = Dog("Fido", "brown")
print(fido.name)
fido.bark()
Classes can also have class attributes, created by assigning variables within the class definition.
These can be accessed from both the class itself and its instances.
class Dog:
legs = 4
def __init__(self, name, color):
self.name = name
self.color = color
fido = Dog("Fido", "brown")
print(fido.legs)
print(Dog.legs)
Class attributes are shared among all instances of the class.
Attempting to access an undefined attribute or method raises an AttributeError.
Inheritance allows sharing functionality between classes.
For example, Cat, Dog, and Rabbit classes may be different, but they might share common properties such as name and color.
Instead of duplicating the same properties in each class, they can inherit from a superclass called Animal.
class Animal:
def __init__(self, name, color):
self.name = name
self.color = color
class Cat(Animal):
def purr(self):
print("Purr...")
class Dog(Animal):
def bark(self):
print("Woof!")
fido = Dog("Fido", "brown")
print(fido.color)
fido.bark()
If a subclass has the same attributes or methods as the superclass, it overrides them.
class Wolf:
def __init__(self, name, color):
self.name = name
self.color = color
def bark(self):
print("Grr...")
class Dog(Wolf):
def bark(self):
print("Woof")
husky = Dog("Max", "grey")
husky.bark()
In the example above,
Wolfis the superclass, andDogis the subclass.
Magic methods are special methods that start and end with double underscores (__).
They define behavior for built-in operations.
One of the most common magic methods is __init__, but there are many more.
For example, operator overloading allows defining custom behavior for operators like + and *.
class Vector2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector2D(self.x + other.x, self.y + other.y)
def toStr(self):
return self.x, self.y
first = Vector2D(5, 7)
second = Vector2D(3, 9)
result = first + second
print(result.toStr())
| Magic Method | Operator |
|---|---|
__add__ |
+ |
__sub__ |
- |
__mul__ |
* |
__truediv__ |
/ |
Class methods are called on the class itself, not an instance.
They are commonly used for alternative constructors.
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def calculate_area(self):
return self.width * self.height
@classmethod
def new_square(cls, side_length):
return cls(side_length, side_length)
square = Rectangle.new_square(5)
print(square.calculate_area())
Static methods are similar, but they do not receive a cls or self argument.
They are regular functions inside a class.
class Pizza:
def __init__(self, toppings):
self.toppings = toppings
@staticmethod
def validate_topping(topping):
if topping == "pineapple":
raise ValueError("No pineapples!")
else:
return True
:one: Try out the code from the examples in the instructions and verify their functionality.
:two: Write a simple class Student with attributes for name and student ID. Create three different objects of this class.
:three: Write a class Person with attributes name and surname. Modify the Student class to inherit from Person and add the student ID attribute. Create three different objects and display their details.
:four: Add a method to Student that prints:
“Hello, my name is name surname, and my student ID is student_ID.”
:five: Write a class Number with an attribute storing a number. Override a magic method to perform the operation:
x² + 2xy + y
:six: Modify the Dog class below to include a static method that prints the total number of dog objects and their names. Test it with at least two objects.
class Dog:
count = 0
dogs = []
def __init__(self, name):
self.name = name
Dog.count += 1
Dog.dogs.append(name)
def bark(self, n):
print("{} says: {}".format(self.name, "woof! " * n))
:six: Add a method to set _pineapple_allowed_ dynamically.