В Python можно создать итератор из коллекции, используя встроенную функцию
iter()
. Итераторы – это объекты, которые реализуют метод __iter__()
и метод __next__()
. Давайте рассмотрим, как это работает на примере.Рассмотрим список, который является одной из стандартных коллекций в Python:
my_list = [1, 2, 3, 4, 5]
Чтобы создать итератор из этого списка, используем функцию
iter()
:my_iterator = iter(my_list)
Теперь
my_iterator
– это итератор, который можно использовать для поочередного доступа к элементам списка.Мы можем использовать функцию
next()
для получения следующего элемента итератора:print(next(my_iterator)) # Выводит: 1
print(next(my_iterator)) # Выводит: 2
print(next(my_iterator)) # Выводит: 3
Когда элементы коллекции заканчиваются,
next()
вызовет исключение StopIteration
.Обычно итераторы используются в сочетании с циклами
for
, что упрощает работу с ними:for item in my_iterator:
print(item)
Если попытаться использовать итератор повторно после его исчерпания, он больше не будет выдавать элементы:
my_iterator = iter(my_list)
for item in my_iterator:
print(item)
# Повторное использование того же итератора:
for item in my_iterator:
print(item) # Ничего не выведет, так как итератор уже исчерпан
Можно создать собственный итератор, определив класс с методами
__iter__()
и __next__()
.Пример:
class MyIterator:
def __init__(self, data):
self.data = data
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index < len(self.data):
result = self.data[self.index]
self.index += 1
return result
else:
raise StopIteration
my_iterable = MyIterator([10, 20, 30])
for item in my_iterable:
print(item)
В этом примере мы создали собственный итератор, который перебирает элементы списка
[10, 20, 30]
.iter()
.__iter__()
и __next__()
для поочередного доступа к элементам.for
для удобства перебора элементов коллекции.Please open Telegram to view this post
VIEW IN TELEGRAM
👍25
Anonymous Quiz
8%
Выражения-генераторы могут быть использованы только в функциях
14%
Выражения-генераторы возвращают список
11%
Выражения-генераторы не поддерживают фильтрацию данных
67%
Выражения-генераторы создают итератор
Для того чтобы создать класс, который поддерживает протокол итератора в Python, нужно определить два метода:
__iter__()
и __next__()
. Давайте рассмотрим пошагово, как это сделать.Начнем с создания класса, который будет содержать коллекцию данных. В данном примере это будет список.
class MyIterable:
def __init__(self, data):
self.data = data
self.index = 0
Метод
__iter__()
должен возвращать сам итератор. В данном случае наш класс сам будет являться итератором, поэтому метод __iter__()
будет возвращать self
.class MyIterable:
def __init__(self, data):
self.data = data
self.index = 0
def __iter__(self):
return self
Метод
__next__()
должен возвращать следующий элемент последовательности. Если элементы закончились, метод должен вызывать исключение StopIteration
.class MyIterable:
def __init__(self, data):
self.data = data
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index < len(self.data):
result = self.data[self.index]
self.index += 1
return result
else:
raise StopIteration
class MyIterable:
def __init__(self, data):
self.data = data
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index < len(self.data):
result = self.data[self.index]
self.index += 1
return result
else:
raise StopIteration
# Создаем объект нашего класса
my_iterable = MyIterable([10, 20, 30, 40, 50])
# Используем его в цикле for
for item in my_iterable:
print(item)
self.data
хранит данные, а self.index
отслеживает текущую позицию в последовательности.__iter__()
возвращает сам объект, так как наш класс будет сам итератором.__next__()
возвращает следующий элемент в последовательности и увеличивает индекс. Если элементов больше нет, вызывается исключение StopIteration
.__iter__()
и __next__()
в вашем классе.__iter__()
должен возвращать объект итератора (обычно self
).__next__()
должен возвращать следующий элемент или вызывать StopIteration
, если элементов больше нет.Please open Telegram to view this post
VIEW IN TELEGRAM
👍13
Anonymous Quiz
4%
isinstance() не поддерживает проверку наследования
5%
isinstance() всегда возвращает True для встроенных типов данных
30%
isinstance() проверяет, имеет ли объект указанный тип данных
61%
isinstance() проверяет, является ли объект экземпляром указанного класса или его подклассов
Статические методы (static methods) в Python используются для создания методов, которые связаны с классом, но не требуют доступа к экземпляру этого класса или к самим данным класса. Это методы, которые выполняют функции, связанные с классом, но не изменяют и не используют состояние экземпляра (атрибуты объекта) или состояние самого класса (атрибуты класса). Они могут быть вызваны на уровне класса, а не на уровне экземпляра класса.
Для создания статического метода в Python используется декоратор
@staticmethod
. Давайте рассмотрим пример:class MyClass:
@staticmethod
def static_method(arg1, arg2):
return arg1 + arg2
Вы можете вызывать статический метод как через сам класс, так и через его экземпляр:
result = MyClass.static_method(5, 10)
print(result) # Вывод: 15
my_instance = MyClass()
result = my_instance.static_method(3, 7)
print(result) # Вывод: 10
self
, что позволяет им изменять состояние конкретного экземпляра класса.class MyClass:
def instance_method(self, value):
self.value = value
cls
, что позволяет им изменять состояние самого класса.class MyClass:
class_variable = 0
@classmethod
def class_method(cls, value):
cls.class_variable = value
self
или cls
в качестве первого аргумента и не могут изменять состояние экземпляра или класса.class MyClass:
@staticmethod
def static_method(arg1, arg2):
return arg1 + arg2
@staticmethod
.Please open Telegram to view this post
VIEW IN TELEGRAM
👍12
Anonymous Quiz
2%
str() вызывается при сравнении объектов
1%
str() вызывается при удалении объекта
4%
str() вызывается при создании нового экземпляра класса
93%
str() вызывается при преобразовании объекта в строку с помощью str()
💊24❤2👀2
Методы класса (class methods) в Python используются для методов, которые работают с самим классом, а не с его экземплярами. Они позволяют изменять состояние класса или выполнять операции, которые относятся ко всему классу в целом, а не к отдельным его экземплярам.
Для создания метода класса в Python используется декоратор
@classmethod
. Такие методы принимают первым аргументом не self
(как в методах экземпляра), а cls
, что указывает на сам класс.Пример:
class MyClass:
class_variable = 0
@classmethod
def class_method(cls, value):
cls.class_variable = value
Метод класса можно вызывать как на уровне класса, так и через экземпляры класса:
# Вызов метода класса через сам класс
MyClass.class_method(10)
print(MyClass.class_variable) # Вывод: 10
# Вызов метода класса через экземпляр класса
instance = MyClass()
instance.class_method(20)
print(MyClass.class_variable) # Вывод: 20
Фабричный метод — это метод класса, который возвращает новый экземпляр класса. Рассмотрим пример, где метод класса используется для создания объекта с предустановленными значениями.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
@classmethod
def from_birth_year(cls, name, birth_year):
age = 2024 - birth_year
return cls(name, age)
# Создание экземпляра через основной конструктор
person1 = Person("Alice", 30)
print(person1.name, person1.age) # Вывод: Alice 30
# Создание экземпляра через фабричный метод
person2 = Person.from_birth_year("Bob", 1990)
print(person2.name, person2.age) # Вывод: Bob 34
self
).class MyClass:
def instance_method(self, value):
self.value = value
@staticmethod
).class MyClass:
@staticmethod
def static_method(arg1, arg2):
return arg1 + arg2
@classmethod
).class MyClass:
class_variable = 0
@classmethod
def class_method(cls, value):
cls.class_variable = value
@classmethod
и принимают cls
в качестве первого аргумента.Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Anonymous Quiz
3%
zip() работает только с числовыми последовательностями
54%
zip() объединяет несколько последовательностей в одну, возвращая итератор
3%
zip() изменяет исходные последовательности
41%
zip() объединяет несколько последовательностей в одну, возвращая список
Обычные методы и методы класса в Python различаются в основном тем, к чему они привязаны и как используются. Давайте рассмотрим их отличия более подробно.
Привязка к экземпляру:
self
, который указывает на текущий экземпляр класса.Использование атрибутов: Могут изменять состояние экземпляра, то есть работать с его атрибутами.
Определение:
class MyClass:
def instance_method(self, value):
self.value = value
Вызов:
instance = MyClass()
instance.instance_method(10)
Пример:
class Dog:
def __init__(self, name):
self.name = name
def bark(self):
print(f"{self.name} говорит: Гав-гав!")
dog = Dog("Бобик")
dog.bark() # Вывод: Бобик говорит: Гав-гав!
Привязка к классу:
cls
, который указывает на сам класс.Использование атрибутов: Могут изменять состояние класса, то есть работать с атрибутами класса.
Определение:
class MyClass:
class_variable = 0
@classmethod
def class_method(cls, value):
cls.class_variable = value
Вызов: Могут вызываться как через сам класс, так и через его экземпляры.
MyClass.class_method(10)
instance = MyClass()
instance.class_method(20)
Пример:
class Dog:
total_dogs = 0
def __init__(self, name):
self.name = name
Dog.total_dogs += 1
@classmethod
def get_total_dogs(cls):
return cls.total_dogs
dog1 = Dog("Бобик")
dog2 = Dog("Шарик")
print(Dog.get_total_dogs()) # Вывод: 2
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍20❤1
Anonymous Quiz
86%
init() вызывается при создании нового экземпляра класса, инициализируя его атрибуты
2%
init() вызывается при удалении экземпляра класса
3%
init() нельзя переопределять в пользовательских классах
9%
init() вызывается при каждом вызове метода класса
👍12
Внедрение зависимостей (Dependency Injection, DI) — это дизайн-паттерн, используемый в объектно-ориентированном программировании для управления зависимостями между объектами. Внедрение зависимостей позволяет сделать код более гибким, тестируемым и поддерживаемым, отделяя создание объектов от их использования.
Car
использует объект Engine
, то Engine
является зависимостью для Car
.Рассмотрим пример, где класс
Car
зависит от класса Engine
.class Engine:
def start(self):
print("Engine started")
class Car:
def __init__(self, engine):
self.engine = engine
def start(self):
self.engine.start()
print("Car started")
# Создание объекта Engine
engine = Engine()
# Внедрение зависимости Engine в объект Car через конструктор
car = Car(engine)
car.start()
Внедрения через методы (сеттеры)
class Engine:
def start(self):
print("Engine started")
class Car:
def __init__(self):
self.engine = None
def set_engine(self, engine):
self.engine = engine
def start(self):
if self.engine is not None:
self.engine.start()
print("Car started")
else:
print("No engine to start")
# Создание объекта Engine
engine = Engine()
# Создание объекта Car
car = Car()
# Внедрение зависимости Engine в объект Car через метод
car.set_engine(engine)
car.start()
Внедрения через свойства
class Engine:
def start(self):
print("Engine started")
class Car:
def __init__(self):
self._engine = None
@property
def engine(self):
return self._engine
@engine.setter
def engine(self, engine):
self._engine = engine
def start(self):
if self._engine is not None:
self._engine.start()
print("Car started")
else:
print("No engine to start")
# Создание объекта Engine
engine = Engine()
# Создание объекта Car
car = Car()
# Внедрение зависимости Engine в объект Car через свойство
car.engine = engine
car.start()
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤2
Anonymous Quiz
15%
Декораторы не могут быть вложены друг в друга
65%
Декораторы могут изменить аргументы и возвращаемое значение функции
11%
Декораторы применяются только к методам класса
9%
Декораторы не поддерживают передачу аргументов
👍9
Когда в Python используется наследование, и у родительских классов есть методы с одинаковым названием, происходит так называемое разрешение имен. Поведение зависит от способа вызова метода и от того, как определены классы.
Если у вас есть множественное наследование, то порядок разрешения методов (MRO, Method Resolution Order) определяет, какой метод будет вызван. Python использует алгоритм C3-линеаризации для вычисления MRO.
class A:
def say_hello(self):
print("Hello from A")
class B:
def say_hello(self):
print("Hello from B")
class C(A, B):
pass
c = C()
c.say_hello()
В примере выше класс
C
наследует от классов A
и B
. Метод say_hello
есть в обоих родительских классах. Порядок разрешения методов в классе C
будет таким: C -> A -> B
. Чтобы увидеть MRO, можно использовать метод __mro__
или функцию mro()
:print(C.__mro__)
# (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
print(C.mro())
# [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
Таким образом, при вызове
c.say_hello()
будет вызван метод say_hello
класса A
, так как он идет первым в MRO.Если вы переопределите метод в дочернем классе, то будет вызван метод, определенный в самом дочернем классе:
class A:
def say_hello(self):
print("Hello from A")
class B:
def say_hello(self):
print("Hello from B")
class C(A, B):
def say_hello(self):
print("Hello from C")
c = C()
c.say_hello()
# Вывод: Hello from C
Иногда необходимо явно вызвать метод одного из родительских классов. Для этого используется функция
super()
, которая возвращает объект, через который можно вызывать методы родительского класса.class A:
def say_hello(self):
print("Hello from A")
class B:
def say_hello(self):
print("Hello from B")
class C(A, B):
def say_hello(self):
super().say_hello()
print("Hello from C")
c = C()
c.say_hello()
# Вывод:
# Hello from A
# Hello from C
Можно вызвать его напрямую через имя класса:
class A:
def say_hello(self):
print("Hello from A")
class B:
def say_hello(self):
print("Hello from B")
class C(A, B):
def say_hello(self):
A.say_hello(self)
B.say_hello(self)
print("Hello from C")
c = C()
c.say_hello()
# Вывод:
# Hello from A
# Hello from B
# Hello from C
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍25🔥1
Anonymous Quiz
58%
GIL предотвращает выполнение нескольких потоков одновременно
20%
GIL предотвращает выполнение нескольких процессов одновременно
10%
GIL улучшает производительность многопоточных программ
12%
GIL необходим для работы асинхронного кода
👍6
Когезия (cohesion) и связность (coupling) — это два важных концепта в программировании, которые влияют на качество и структуру кода.
Когезия относится к степени, в которой элементы внутри модуля (например, класса или функции) связаны друг с другом и работают вместе для выполнения одной задачи. Высокая когезия означает, что элементы модуля сильно связаны и направлены на выполнение одной функции, что делает модуль более понятным и легким для сопровождения.
Класс, выполняющий одну задачу:
class FileHandler:
def read_file(self, filename):
with open(filename, 'r') as file:
return file.read()
def write_file(self, filename, data):
with open(filename, 'w') as file:
file.write(data)
Функция, выполняющая одну конкретную задачу:
def calculate_sum(numbers):
return sum(numbers)
Преимущества высокой когезии:
Связность относится к степени зависимости одного модуля от другого. Высокая связность означает, что модули сильно зависят друг от друга, что делает систему более жесткой и сложной для сопровождения. Низкая связность, напротив, означает, что модули имеют минимальные зависимости друг от друга, что делает систему более гибкой и легко модифицируемой.
Использование интерфейсов или абстракций:
class Database:
def connect(self):
pass
class MySQLDatabase(Database):
def connect(self):
print("Connecting to MySQL database")
class PostgreSQLDatabase(Database):
def connect(self):
print("Connecting to PostgreSQL database")
def initialize_db(db: Database):
db.connect()
db = MySQLDatabase()
initialize_db(db)
Внедрение зависимостей:
class Service:
def __init__(self, repository):
self.repository = repository
def perform_action(self):
self.repository.save("Some data")
class Repository:
def save(self, data):
print(f"Saving {data}")
repository = Repository()
service = Service(repository)
service.perform_action()
Преимущества низкой связности:
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15😁1
Anonymous Quiz
19%
del() вызывается при доступе к элементу объекта по индексу
3%
del() вызывается при создании нового экземпляра класса
4%
del() вызывается при изменении атрибута объекта
74%
del() вызывается перед удалением объекта сборщиком мусора
Порождающие паттерны (creational patterns) — это шаблоны проектирования в объектно-ориентированном программировании, которые предназначены для управления процессом создания объектов.
Одиночка (Singleton): Паттерн Одиночка гарантирует, что у класса будет только один экземпляр, и предоставляет глобальную точку доступа к нему.
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls._instance
singleton1 = Singleton()
singleton2 = Singleton()
print(singleton1 is singleton2) # True
Фабричный метод (Factory Method): Фабричный метод определяет интерфейс для создания объекта, но позволяет подклассам изменять тип создаваемых объектов.
class Animal:
def speak(self):
raise NotImplementedError("Subclass must implement abstract method")
class Dog(Animal):
def speak(self):
return "Woof!"
class Cat(Animal):
def speak(self):
return "Meow!"
class AnimalFactory:
@staticmethod
def get_animal(animal_type):
if animal_type == "dog":
return Dog()
elif animal_type == "cat":
return Cat()
else:
return None
dog = AnimalFactory.get_animal("dog")
cat = AnimalFactory.get_animal("cat")
print(dog.speak()) # Woof!
print(cat.speak()) # Meow!
Абстрактная фабрика (Abstract Factory): Абстрактная фабрика предоставляет интерфейс для создания семейств связанных или зависимых объектов без указания их конкретных классов.
class Dog:
def speak(self):
return "Woof!"
class Cat:
def speak(self):
return "Meow!"
class PetFactory:
def create_dog(self):
return Dog()
def create_cat(self):
return Cat()
factory = PetFactory()
dog = factory.create_dog()
cat = factory.create_cat()
print(dog.speak()) # Woof!
print(cat.speak()) # Meow!
Строитель (Builder): Паттерн Строитель используется для создания сложных объектов пошагово. Он позволяет создавать разные представления объекта, используя один и тот же код.
class House:
def __init__(self):
self.walls = None
self.roof = None
self.windows = None
def __str__(self):
return f"House with {self.walls} walls, {self.roof} roof, and {self.windows} windows."
class HouseBuilder:
def __init__(self):
self.house = House()
def build_walls(self, walls):
self.house.walls = walls
return self
def build_roof(self, roof):
self.house.roof = roof
return self
def build_windows(self, windows):
self.house.windows = windows
return self
def build(self):
return self.house
builder = HouseBuilder()
house = builder.build_walls("brick").build_roof("tile").build_windows("double-glazed").build()
print(house)
# House with brick walls, tile roof, and double-glazed windows.
Прототип (Prototype): Паттерн Прототип создает новые объекты путем копирования существующих экземпляров (прототипов).
import copy
class Prototype:
def __init__(self, value):
self.value = value
def clone(self):
return copy.deepcopy(self)
original = Prototype(10)
clone = original.clone()
print(original.value) # 10
print(clone.value) # 10
clone.value = 20
print(original.value) # 10
print(clone.value) # 20
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍26❤2
Anonymous Quiz
12%
Аннотации типов обязательно должны быть указаны для всех аргументов функции
71%
Аннотации типов используются только для документации и статической проверки типов
12%
Аннотации типов автоматически выполняют приведение типов
5%
Аннотации типов изменяют поведение функции во время выполнения
Абстрактная фабрика (Abstract Factory) — это порождающий паттерн проектирования, который предоставляет интерфейс для создания семейств взаимосвязанных или взаимозависимых объектов без указания их конкретных классов. Этот паттерн позволяет создавать комплекты объектов, которые должны работать вместе, обеспечивая при этом их взаимозаменяемость.
Создание абстрактных продуктов: Рассмотрим пример, в котором абстрактная фабрика создает различные виды кнопок и чекбоксов для двух разных операционных систем: Windows и MacOS.
from abc import ABC, abstractmethod
class Button(ABC):
@abstractmethod
def click(self):
pass
class Checkbox(ABC):
@abstractmethod
def check(self):
pass
Создание конкретных продуктов
class WindowsButton(Button):
def click(self):
print("Windows button clicked")
class MacOSButton(Button):
def click(self):
print("MacOS button clicked")
class WindowsCheckbox(Checkbox):
def check(self):
print("Windows checkbox checked")
class MacOSCheckbox(Checkbox):
def check(self):
print("MacOS checkbox checked")
Создание абстрактной фабрики
class GUIFactory(ABC):
@abstractmethod
def create_button(self) -> Button:
pass
@abstractmethod
def create_checkbox(self) -> Checkbox:
pass
Создание конкретных фабрик
class WindowsFactory(GUIFactory):
def create_button(self) -> Button:
return WindowsButton()
def create_checkbox(self) -> Checkbox:
return WindowsCheckbox()
class MacOSFactory(GUIFactory):
def create_button(self) -> Button:
return MacOSButton()
def create_checkbox(self) -> Checkbox:
return MacOSCheckbox()
Использование абстрактной фабрики
def client_code(factory: GUIFactory):
button = factory.create_button()
checkbox = factory.create_checkbox()
button.click()
checkbox.check()
# Клиентский код может работать с любыми фабриками и продуктами
windows_factory = WindowsFactory()
macos_factory = MacOSFactory()
print("Client: Testing client code with Windows factory:")
client_code(windows_factory)
print("\nClient: Testing client code with MacOS factory:")
client_code(macos_factory)
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7