Урок 27. Ітератори та генератори

Ітератори в Python — це об’єкти, які дозволяють перебирати елементи колекції (наприклад, списків, кортежів, словників, множин) по одному за раз. Вони реалізують протокол ітерації, що складається з двох методів: __iter__() і __next__(). Ітератори є корисними для економії пам’яті, оскільки вони генерують елементи на льоту, не зберігаючи всю колекцію в пам’яті. Приклад з відео:

#Ітератор - це об'єкт, 
#який містить підраховану кількість значень.
#Ітератор — це об’єкт, який можна повторювати, 
#тобто ви можете проходити через усі значення.
#У Python ітератор — це об’єкт, який реалізує 
#протокол ітератора, який складається 
#з методів __iter__() і __next__().
#Списки, кортежі, словники та множини
#є ітерабельними об’єктами.
str1 = "Text"
str1Iterator = iter(str1)
print(str1Iterator)
print(next(str1Iterator))
print(next(str1Iterator))
print(next(str1Iterator))
print(next(str1Iterator))
#print(next(str1Iterator))
list1 = ["Dodge", "Ford", "Toyota"]
list1Iterator = iter(list1)
print(list1Iterator)
print(next(list1Iterator))
print(next(list1Iterator))
print(next(list1Iterator))
for i in list1:
    print(i)

Для створення об’єкта чи класу як ітератора потрібно реалізувати в ньому методи __iter__() та __next__(). Приклад з відео:

#Щоб створити об’єкт/клас як ітератор, 
#вам потрібно реалізувати
#методи __iter__() і __next__() 
#для вашого об’єкта.
#Метод __iter__() завжди повинен 
#повертати сам об’єкт ітератора.
#Метод __next__() також дозволяє 
#виконувати операції, і має повернути 
#наступний елемент у послідовності.
class IncreaseByOne:
    def __iter__(self):
        self.num = 1
        return self
    def __next__(self):
        nextnum = self.num
        self.num += 1
        return nextnum
    
instance1 = IncreaseByOne()
iterator1 = iter(instance1)
print(next(iterator1))
print(next(iterator1))
print(next(iterator1))
print(next(iterator1))
print(next(iterator1))

Для уникнення нескінченного виконання ітепацій можна використати StopIteration. Приклад з відео:

#Щоб ітерація не тривала вічно, ми можемо 
#використати оператор StopIteration.
class IncreaseByOne:
    def __iter__(self):
        self.num = 1
        return self
    def __next__(self):
        if self.num<=10:
            nextnum = self.num
            self.num += 1
            return nextnum
        else:
            raise StopIteration
    
instance1 = IncreaseByOne()
iterator1 = iter(instance1)
for i in iterator1:
    print(i)

Генератори

Генератори — це простіший спосіб створення ітераторів. Вони використовують оператор yield, щоб повернути значення на льоту без необхідності реалізовувати методи __iter__() і __next__(). Приклад з відео:

#У Python генератор — це функція, 
#яка повертає ітератор
#Ми можемо визначити функцію генератора 
#за допомогою ключового слова def,
#але замість оператора return ми 
#використовуємо оператор yield.
#Ключове слово yield використовується 
#для створення значення з генератора.
#Коли викликається функція генератора, 
#вона не виконує тіло функції негайно. 
#Натомість він повертає об’єкт-генератор, 
#який можна повторити, щоб отримати значення.
def increaseByOneGenerator(n):
    num = 0
    while num<n:
        yield num
        num+=1
        
for i in increaseByOneGenerator(10):
    print(i)
print("---------------")
generator1 = increaseByOneGenerator(25)
print(next(generator1))
print(next(generator1))
print(next(generator1))
for i in generator1:
    print(i)

Приклад з відео із застосуванням спрощеного синтаксису для генераторів:

#expression for item in iterable
#Вираз-генератор створює об’єкт-генератор, 
#який виробляє значення виразу для кожного 
#елемента об’єкта, що повторюється, 
#по одному під час кожної ітерації.
squareGenerator = (num*num for num in range(10))
for i in squareGenerator:
    print(i)
Урок 27. Ітератори та генератори

В цьому відео поговоримо про ітератори та генератори.

Приклади на Github

Урок 26. Поліморфізм

Поліморфізм в Python — це принцип об’єктно-орієнтованого програмування, що дозволяє об’єктам різних класів оброблятися через єдиний інтерфейс. Це означає, що одна й та ж операція може мати різні реалізації для різних типів об’єктів. Поліморфізм підвищує гнучкість і зручність використання коду. Приклад поліморфізму з відео на ілюстрації застосування функції len() з об’єктами різних класів:

#Слово «поліморфізм» означає «багато форм», 
#і в програмуванні воно відноситься до 
#методів/функцій/операторів з однаковою назвою, 
#які можуть виконуватися для багатьох об’єктів або класів.
#Наприклад функція len().
str1 = "Python is a solid choice."
print(len(str1))
list1 = ["Dodge", "Ford", "Toyota"]
print(len(list1))
tuple1 = ("Lincoln", "Honda", "Alfa Romeo")
print(len(tuple1))

Приклад поліморфізму з відео із застосування методу sound() для об’єктів різних класів:

#Слово «поліморфізм» означає «багато форм», 
#і в програмуванні воно відноситься до 
#методів/функцій/операторів з однаковою назвою, 
#які можуть виконуватися для багатьох 
#об’єктів або класів.
class Cat:
    def sound(self):
        print("Meow, meow, meow")
        
class Dog:
    def sound(self):
        print("Woof, woof, woof")
        
cat1 = Cat()
dog1 = Dog()
cat1.sound()
dog1.sound()

Поліморфізм можна використовувати у комбінації з наслідуванням. Приклад з відео:

#Ми можемо використовувати поліморфізм 
#із класами наслідування
class Animal:
    def sound(self):
        print("Animal sound")
    
class Cat(Animal):
    def sound(self):
        print("Meow")
        
class Dog(Animal):
    def sound(self):
        print("Woof")
        
cat1 = Cat()
dog1 = Dog()
cat1.sound()
dog1.sound()
Урок 26. Поліморфізм

В цьому відео поговоримо про поліморфізм (важлива концепція ООП).

Приклади на Github

Урок 25. Наслідування

Ілюстрація з відео для пояснення потреби в наслідуванні:

#Навіщо нам наслідування?
class Person:
    def __init__(self, name, surname):
        self.name = name
        self.surname = surname
        
class Student:
    def __init__(self, name, surname):
        self.name = name
        self.surname = surname
        
person1 = Person("John", "Smith")
student1 = Student("Jenny", "Jackson")
print(person1.name, person1.surname)
print(student1.name,student1.surname)

Наслідування в Python — це один з основних принципів об’єктно-орієнтованого програмування, який дозволяє створювати нові класи на основі вже існуючих. Це дозволяє повторно використовувати код, спрощує його підтримку та забезпечує більш організовану структуру. Клас, який наслідується, називається “батьківським” (або “базовим”), а новий клас, що його наслідує, — “дочірнім”. Приклад з відео:

#Inheritance (наслідування) 
#дозволяє нам визначити клас, 
#який успадковує всі методи
#та властивості з іншого класу.
#Батьківський клас — це клас, який успадковується, 
#також називається базовим класом.
#Дочірній клас - це клас, який успадковує інший клас,
#також називається похідним класом.
class Person:
    def __init__(self, name, surname):
        self.name = name
        self.surname = surname
        
class Student(Person):
    pass
        
person1 = Person("John", "Smith")
student1 = Student("Jenny", "Jackson")
print(person1.name, person1.surname)
print(student1.name,student1.surname)

Функція super()

В Python є функція super(), яка дозволяє дочірньому класу наслідувати властивості від батьківського. Приклад з відео:

#Python також має функцію super(), 
#яка змусить дочірній клас успадкувати 
#всі методи та властивості від 
#свого батьківського класу.
class Person:
    def __init__(self, name, surname):
        self.name = name
        self.surname = surname
        
class Student(Person):
    def __init__(self, name, surname, averageMark):
        super().__init__(name, surname)
        self.averageMark = averageMark
        
person1 = Person("John", "Smith")
student1 = Student("Jenny", "Jackson", 3.5)
print(person1.name, person1.surname)
print(student1.name,student1.surname, student1.averageMark)

Множинне наслідування

Множинне наслідування в Python — це можливість створення дочірнього класу, який наслідує від кількох батьківських класів одночасно. Це дозволяє об’єднувати властивості та методи декількох класів, що може бути корисним у складних системах, де потрібно інтегрувати функціональність з різних джерел. Приклад з відео:

#Python підтримує множинне наслідування
class PythonDeveloper:
    def projectPython(self):
        print("Python coding in process.")
        
class JavaDeveloper:
    def projectJava(self):
        print("Java coding in process.")
        
class PythonJavaDeveloper(PythonDeveloper, JavaDeveloper):
    pass

developer1 = PythonJavaDeveloper()
developer1.projectPython()
developer1.projectJava()

Функція isinstance()

Функція isinstance() в Python використовується для перевірки, чи є об’єкт певного типу або чи належить він до певного класу (або підкласу). Вона повертає True, якщо об’єкт є екземпляром вказаного класу або його підкласу, і False в іншому випадку. Приклад з відео:

#Функція isinstance допомагає 
#перевірити тип об'єкта
class PythonDeveloper:
    def projectPython(self):
        print("Python coding in process.")
        
class JavaDeveloper:
    def projectJava(self):
        print("Java coding in process.")
        
developer1 = JavaDeveloper()

if isinstance(developer1,PythonDeveloper):
    print("This is PythonDeveloper object.")
    
elif isinstance(developer1, JavaDeveloper):
    print("This is JavaDeveloper object.")
    
else:
    print("Unknown object type.")
Уроки 25. Уроки наслідування

В цьому відео поговоримо про наслідування (важлива концепція ООП).

Приклади на Github

Урок 24. Інкапсуляція

Атрибути класів за помовчанням доступні або публічні (public), що надає можливість їх змінювати. Приклад з відео:

#Атрибути класу доступні за замовчуванням, 
#що означає, що ви можете їх змінити.
class Person:
    def __init__(self, name, surname, age):
        self.name = name
        self.surname = surname
        self.age = age
        
    def displayFunc(self):
        print(f"Name: {self.name} Surname:{self.surname} Age:{self.age}")
        
person1 = Person("John", "Smith", 35)
person1.displayFunc()
person1.age = -200
person1.surname = "InvalidSurname"
person1.name = "InvalidName"
person1.displayFunc()
print(person1.surname)

Інкапсуляція у Python — це принцип об’єктно-орієнтованого програмування, що полягає в приховуванні даних об’єкта та наданні доступу до них лише через визначені методи. Це дозволяє контролювати, як дані використовуються, забезпечуючи безпеку і запобігаючи випадковим змінам. У Python для цього використовують односторонній доступ до атрибутів, позначаючи їх як приватні, за допомогою одного або двох підкреслень.

Варіанти модифікаторів доступу:

  • self.name = name – public, доступні звідусіль
  • self._name = name – protected, доступні в межах класу та підкласів
  • self.__name = name – private, доступні в межах класу

Для того щоб зробити змінну приватною треба додати два підкреслення на початку назви змінної. Приклад з відео:

#Ми можемо захистити змінні в класі, 
#позначивши їх приватними.
#Щоб визначити приватну змінну, 
#додайте два підкреслення як префікс
#на початку назви змінної.
#self.__age
class Person:
    def __init__(self, name, surname, age):
        self.__name = name
        self.__surname = surname
        self.__age = age
        
    def displayFunc(self):
        print(f"Name:{self.__name} Surname:{self.__surname} Age:{self.__age}")
        
person1 = Person("John", "Smith", 35)
person1.displayFunc()
#print(person1.__age)
#print(person1.__surname)
#print(person1.__name)

Приклад з відео із застосуванням методу displayFunc() для виведення атрибутів об’єкта класу Person і спробою внесення змін у приватні атрибути:

class Person:
    def __init__(self, name, surname, age):
        self.__name = name
        self.__surname = surname
        self.__age = age
        
    def displayFunc(self):
        print(f"Name:{self.__name} Surname:{self.__surname} Age:{self.__age}")
        
person1 = Person("John", "Smith", 35)
person1.displayFunc()
person1.__name = "James"
person1.__surname = "Johns"
person1.__age = 25
print("--------------")
person1.displayFunc()
print(person1.__age)
print(person1.__surname)
print(person1.__name)
person2 = Person("Jenny", "Jackson", 30)
person2.displayFunc()
print(person2.__age)

Геттери та сеттери

Для внесення змін у приватні атрибути можна використовувати спеціальні методи: setter method (сеттери) – для внесення змін у визначені атрибути класу, getter method (геттери) – для отримання поточних даних з атрибутів класу. Прикладі з відео:

class Person:
    def __init__(self, surname, age):
        self.__surname = surname
        self.__age = age
        
    #setter method
    def setAge(self, age):
        if 1<age<120:
            self.__age=age
            
        else:
            print("Invalid age input.")
    #getter method            
    def getAge(self):
        return self.__age

person1 = Person("Smith", 35)
print(person1.getAge())
person1.setAge(33)
print(person1.getAge())
person1.setAge(0)
print(person1.getAge())
print(person1.__surname)

Замість методів геттерів та сеттерів можна використовувати так звані властивості геттерів та сеттерів. Особливість синтаксису полягає у використанні символу @ для позначення відповідних властивостей. Приклад з відео:

#Щоб створити властивість геттера, 
#використовуйте анотацію @property.
#Щоб створити властивість сеттера, 
#використовуйте анотацію @name.setter.
class Person:
    def __init__(self, surname, age):
        self.__surname = surname
        self.__age = age
        
    @property
    def age(self):
        return self.__age
    
    @age.setter
    def age(self, age):
        if 1<age<120:
            self.__age=age    
        else:
            print("Invalid age input.")
            
person1 = Person("Smith", 35)
print(person1.age)
person1.age = 33
print(person1.age)
person1.age = 150
print(person1.age)
Урок 24. Інкапсуляція

В цьому відео поговоримо про інкапсуляцію (важлива концепція ООП).

Приклади на Github