Programming Python

Tasks studies - laboratory


Project maintained by dawidolko Hosted on GitHub Pages — Theme by dawidolko

Review Assignment Due Date

Scripting Language Lab5

Object-Oriented Programming

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__ Method

The __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.

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.


Methods

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

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, Wolf is the superclass, and Dog is the subclass.


Magic Methods

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__ /

Static and Class Methods

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

Tasks to Complete

: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.

:exclamation: Tasks 2-7 must be added to GitHub :exclamation: