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
Anonymous Quiz
8%
enter() вызывается при создании нового экземпляра класса
11%
enter() вызывается при выходе из блока with
72%
enter() вызывается при входе в блок with и должен возвращать объект для использования в блоке
10%
enter() используется для изменения атрибутов объекта
👍2
Паттерн "Строитель" — это порождающий паттерн проектирования, который позволяет создавать сложные объекты пошагово и отделяет процесс конструирования объекта от его представления, что дает возможность использовать один и тот же процесс для создания различных представлений.
Создание продукта
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."
Определение интерфейса строителя
from abc import ABC, abstractmethod
class HouseBuilder(ABC):
@abstractmethod
def build_walls(self):
pass
@abstractmethod
def build_roof(self):
pass
@abstractmethod
def build_windows(self):
pass
@abstractmethod
def get_house(self):
pass
Создание конкретных строителей
class ConcreteHouseBuilder(HouseBuilder):
def __init__(self):
self.house = House()
def build_walls(self):
self.house.walls = "brick"
return self
def build_roof(self):
self.house.roof = "tile"
return self
def build_windows(self):
self.house.windows = "double-glazed"
return self
def get_house(self):
return self.house
Создание директора (опционально)
class Director:
def __init__(self, builder):
self.builder = builder
def construct_house(self):
self.builder.build_walls().build_roof().build_windows()
return self.builder.get_house()
Использование паттерна "Строитель"
# Использование без директора
builder = ConcreteHouseBuilder()
house = builder.build_walls().build_roof().build_windows().get_house()
print(house) # House with brick walls, tile roof, and double-glazed windows.
# Использование с директором
director = Director(builder)
house = director.construct_house()
print(house) # House with brick walls, tile roof, and double-glazed windows.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤3
Anonymous Quiz
82%
enumerate() возвращает пары индекс-значение для каждого элемента последовательности
4%
enumerate() изменяет исходную последовательность
9%
enumerate() возвращает только индексы элементов последовательности
5%
enumerate() работает только с числовыми значениями
🎉5❤1
Это порождающий паттерн проектирования, который определяет интерфейс для создания объекта, но позволяет подклассам изменять тип создаваемого объекта. Это позволяет классу делегировать создание объектов подклассам, таким образом убирая жесткую привязку к конкретным классам и делая систему более гибкой и расширяемой.
Определение интерфейса продукта
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def speak(self):
pass
Создание конкретных продуктов
class Dog(Animal):
def speak(self):
return "Woof!"
class Cat(Animal):
def speak(self):
return "Meow!"
Определение создателя
class AnimalFactory(ABC):
@abstractmethod
def create_animal(self) -> Animal:
pass
def some_operation(self) -> str:
animal = self.create_animal()
return f"The animal says: {animal.speak()}"
Создание конкретных создателей
class DogFactory(AnimalFactory):
def create_animal(self) -> Animal:
return Dog()
class CatFactory(AnimalFactory):
def create_animal(self) -> Animal:
return Cat()
Использование фабричного метода
def client_code(factory: AnimalFactory):
print(factory.some_operation())
dog_factory = DogFactory()
cat_factory = CatFactory()
print("Client: Testing client code with DogFactory:")
client_code(dog_factory) # Вывод: The animal says: Woof!
print("\nClient: Testing client code with CatFactory:")
client_code(cat_factory) # Вывод: The animal says: Meow!
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍2
Anonymous Quiz
55%
hash() должен возвращать уникальное значение для каждого объекта
33%
hash() вызывается при добавлении объекта в хэш-таблицу
2%
hash() вызывается при изменении атрибутов объекта
11%
hash() используется для проверки равенства объектов
🤯7❤2🔥1
Это порождающий паттерн проектирования, который позволяет создавать новые объекты, копируя уже существующие экземпляры. Этот паттерн полезен, когда процесс создания объекта является дорогим (в смысле затрат ресурсов) и трудоемким, а копирование существующего объекта оказывается проще и быстрее.
clone()
, позволяющий клонировать объект.clone()
на прототипах.Определение интерфейса прототипа
from abc import ABC, abstractmethod
import copy
class Shape(ABC):
def __init__(self, id):
self.id = id
@abstractmethod
def clone(self):
pass
Создание конкретных прототипов
class Rectangle(Shape):
def __init__(self, id, width, height):
super().__init__(id)
self.width = width
self.height = height
def clone(self):
return copy.deepcopy(self)
def __str__(self):
return f"Rectangle(id={self.id}, width={self.width}, height={self.height})"
class Circle(Shape):
def __init__(self, id, radius):
super().__init__(id)
self.radius = radius
def clone(self):
return copy.deepcopy(self)
def __str__(self):
return f"Circle(id={self.id}, radius={self.radius})"
Использование прототипа
def main():
rect1 = Rectangle(1, 10, 20)
circle1 = Circle(2, 15)
rect2 = rect1.clone()
circle2 = circle1.clone()
print(rect1) # Rectangle(id=1, width=10, height=20)
print(rect2) # Rectangle(id=1, width=10, height=20)
print(circle1) # Circle(id=2, radius=15)
print(circle2) # Circle(id=2, radius=15)
if __name__ == "__main__":
main()
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Anonymous Quiz
11%
functools.partial() изменяет исходную функцию
15%
functools.partial() удаляет некоторые аргументы из функции
68%
functools.partial() создаёт новую функцию с предопределёнными значениями некоторых аргументов
7%
functools.partial() позволяет функции работать асинхронно
Это паттерны проектирования, которые упрощают создание отношений между объектами, обеспечивая гибкую структуру и способствуя повторному использованию кода. Эти паттерны помогают организовать классы и объекты в большие структуры, сохраняя при этом гибкость и эффективность.
Паттерн Адаптер позволяет объектам с несовместимыми интерфейсами работать вместе. Он оборачивает один из объектов, преобразуя его интерфейс в совместимый.
class EuropeanSocket:
def voltage(self):
return 230
class USASocket:
def voltage(self):
return 120
class Adapter:
def __init__(self, socket):
self.socket = socket
def voltage(self):
return self.socket.voltage()
# Использование
european_socket = EuropeanSocket()
adapter = Adapter(european_socket)
print(adapter.voltage()) # 230
Паттерн Мост разделяет абстракцию и реализацию, позволяя изменять их независимо друг от друга.
class DrawingAPI:
def draw_circle(self, x, y, radius):
pass
class DrawingAPI1(DrawingAPI):
def draw_circle(self, x, y, radius):
print(f"API1.circle at {x}:{y} radius {radius}")
class DrawingAPI2(DrawingAPI):
def draw_circle(self, x, y, radius):
print(f"API2.circle at {x}:{y} radius {radius}")
class Shape:
def __init__(self, drawing_api):
self.drawing_api = drawing_api
def draw(self):
pass
class CircleShape(Shape):
def __init__(self, x, y, radius, drawing_api):
super().__init__(drawing_api)
self.x = x
self.y = y
self.radius = radius
def draw(self):
self.drawing_api.draw_circle(self.x, self.y, self.radius)
# Использование
circle1 = CircleShape(1, 2, 3, DrawingAPI1())
circle2 = CircleShape(5, 7, 11, DrawingAPI2())
circle1.draw() # API1.circle at 1:2 radius 3
circle2.draw() # API2.circle at 5:7 radius 11
Паттерн Компоновщик позволяет группировать объекты в древовидные структуры для представления иерархий "часть-целое".
class Component:
def operation(self):
pass
class Leaf(Component):
def operation(self):
return "Leaf"
class Composite(Component):
def __init__(self):
self.children = []
def add(self, component):
self.children.append(component)
def operation(self):
results = []
for child in self.children:
results.append(child.operation())
return f"Branch({'+'.join(results)})"
# Использование
leaf1 = Leaf()
leaf2 = Leaf()
composite = Composite()
composite.add(leaf1)
composite.add(leaf2)
print(composite.operation()) # Branch(Leaf+Leaf)
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Anonymous Quiz
88%
iter() должен возвращать итератор для объекта
7%
iter() вызывается при создании нового экземпляра класса
4%
iter() используется для изменения атрибутов объекта
0%
iter() вызывается при удалении объекта
💊13❤1
Паттерн "Адаптер" (Adapter) — это структурный паттерн проектирования, который позволяет объектам с несовместимыми интерфейсами работать вместе. Адаптер оборачивает один из объектов и преобразует его интерфейс в интерфейс, который ожидает клиент. Этот паттерн часто используется для интеграции кода с устаревшими библиотеками или компонентами.
Целевой интерфейс (Target Interface): Интерфейс, который ожидает клиент.
Клиент (Client): Объект, который использует целевой интерфейс для взаимодействия с другими объектами.
Адаптируемый интерфейс (Adaptee): Существующий интерфейс, который необходимо адаптировать.
Адаптер (Adapter): Класс, который оборачивает адаптируемый интерфейс и преобразует его в целевой интерфейс.
Определение целевого интерфейса и адаптируемого интерфейса
class EuropeanSocketInterface:
def voltage(self):
pass
def live(self):
pass
def neutral(self):
pass
def earth(self):
pass
class USASocket:
def voltage(self):
return 120
def live(self):
return 1
def neutral(self):
return -1
Создание адаптера
class Adapter(EuropeanSocketInterface):
def __init__(self, usa_socket):
self.usa_socket = usa_socket
def voltage(self):
return self.usa_socket.voltage()
def live(self):
return self.usa_socket.live()
def neutral(self):
return self.usa_socket.neutral()
def earth(self):
return 0 # В американских розетках может не быть заземления
Использование адаптера
def client_code(socket):
print(f"Voltage: {socket.voltage()}V")
print(f"Live: {socket.live()}")
print(f"Neutral: {socket.neutral()}")
print(f"Earth: {socket.earth()}")
# Использование
usa_socket = USASocket()
adapter = Adapter(usa_socket)
client_code(adapter)
Объектный адаптер: Использует композицию для оборачивания объекта.
Классовый адаптер: Использует множественное наследование для адаптации одного интерфейса к другому.
Пример классового адаптера:
class USASocket:
def voltage(self):
return 120
def live(self):
return 1
def neutral(self):
return -1
class EuropeanSocketInterface:
def voltage(self):
pass
def live(self):
pass
def neutral(self):
pass
def earth(self):
pass
class Adapter(EuropeanSocketInterface, USASocket):
def earth(self):
return 0 # В американских розетках может не быть заземления
# Использование
adapter = Adapter()
client_code(adapter)
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤4
Anonymous Quiz
80%
missing() вызывается при попытке доступа к отсутствующему ключу в словаре
9%
missing() вызывается при создании нового экземпляра класса
6%
missing() используется для удаления ключей из словаря
6%
missing() вызывается при добавлении нового ключа в словарь
❤1
Это структурный шаблон проектирования, который предоставляет объект, управляющий доступом к другому объекту. Этот паттерн создаёт суррогат или заместителя для другого объекта и контролирует доступ к нему.
Когда необходимо контролировать доступ к ресурсу.
Когда необходимо отложить создание ресурсоёмких объектов до момента их первого использования.
Для управления ресурсами, такими как память или сетевые соединения.
Для добавления дополнительной функциональности, такой как логирование или кэширование, без изменения кода основного объекта.
Контролирует доступ к объекту, создавая его по требованию.
Контролирует доступ к объекту, ограничивая права пользователей.
Управляет доступом к объекту, находящемуся в другом адресном пространстве.
Кэширует результаты запросов к объекту для повышения производительности.
Заместитель реализует интерфейс основного объекта и перенаправляет вызовы к реальному объекту, добавляя при этом дополнительную функциональность. В этом примере класс
Proxy
контролирует доступ к классу RealSubject
, добавляя проверку доступа и логирование.from abc import ABC, abstractmethod
class Subject(ABC):
@abstractmethod
def request(self):
pass
class RealSubject(Subject):
def request(self):
print("Реальный объект: Обработка запроса.")
class Proxy(Subject):
def __init__(self, real_subject):
self._real_subject = real_subject
def request(self):
if self.check_access():
self._real_subject.request()
self.log_access()
def check_access(self):
print("Заместитель: Проверка доступа перед выполнением запроса.")
return True
def log_access(self):
print("Заместитель: Логирование времени запроса.")
# Клиентский код
real_subject = RealSubject()
proxy = Proxy(real_subject)
proxy.request()
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤1
Anonymous Quiz
6%
Аннотации типов обязательно должны быть указаны для всех аргументов функции
11%
Аннотации типов автоматически выполняют приведение типов
80%
Аннотации типов используются только для документации и статической проверки типов
3%
Аннотации типов изменяют поведение функции во время выполнения
Поведенческие паттерны — это тип шаблонов проектирования, которые сосредоточены на взаимодействии объектов и классов. Их основная цель — упростить и улучшить коммуникацию между объектами, сделать систему более гибкой и легкой для сопровождения.
Поведенческие паттерны помогают организовать взаимодействие объектов таким образом, чтобы они могли легко и эффективно обмениваться данными и выполнять совместные задачи.
Эти паттерны обеспечивают гибкость в изменении алгоритмов и методов работы объектов без изменения их классов.
Поведенческие паттерны способствуют соблюдению принципов SOLID, особенно принципа единственной ответственности и принципа открытости/закрытости.
Стратегия (Strategy)
Позволяет выбирать алгоритм на основе контекста, без изменения класса, который его использует.
from abc import ABC, abstractmethod
class Strategy(ABC):
@abstractmethod
def execute(self, data):
pass
class ConcreteStrategyA(Strategy):
def execute(self, data):
return sorted(data)
class ConcreteStrategyB(Strategy):
def execute(self, data):
return sorted(data, reverse=True)
class Context:
def __init__(self, strategy: Strategy):
self._strategy = strategy
def set_strategy(self, strategy: Strategy):
self._strategy = strategy
def execute_strategy(self, data):
return self._strategy.execute(data)
data = [5, 2, 9, 1]
context = Context(ConcreteStrategyA())
print(context.execute_strategy(data)) # [1, 2, 5, 9]
context.set_strategy(ConcreteStrategyB())
print(context.execute_strategy(data)) # [9, 5, 2, 1]
Наблюдатель (Observer)
Определяет зависимость "один ко многим" между объектами таким образом, что при изменении состояния одного объекта все зависимые объекты оповещаются и обновляются автоматически.
class Subject:
def __init__(self):
self._observers = []
def add_observer(self, observer):
self._observers.append(observer)
def remove_observer(self, observer):
self._observers.remove(observer)
def notify_observers(self, message):
for observer in self._observers:
observer.update(message)
class Observer:
def update(self, message):
pass
class ConcreteObserver(Observer):
def update(self, message):
print(f"Observer received: {message}")
subject = Subject()
observer1 = ConcreteObserver()
observer2 = ConcreteObserver()
subject.add_observer(observer1)
subject.add_observer(observer2)
subject.notify_observers("Hello Observers!") # Observer received: Hello Observers!
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Anonymous Quiz
14%
getattr() вызывается при создании нового экземпляра класса
5%
getattr() используется для удаления атрибутов объекта
44%
getattr() вызывается при попытке доступа к несуществующему атрибуту объекта
37%
getattr() вызывается при изменении значения атрибута объекта
👍1
Цепочка ответственности (Chain of Responsibility) — это поведенческий паттерн проектирования, который позволяет передавать запрос по цепочке потенциальных обработчиков, пока один из них не обработает запрос. Этот паттерн избавляет отправителя запроса от необходимости знать, какой объект в цепочке обработает его запрос.
Позволяет разделить обязанности между различными обработчиками, каждый из которых решает, обработать ли запрос или передать его следующему обработчику в цепочке.
Обработчики могут легко добавляться или удаляться из цепочки без изменения кода других обработчиков или отправителя.
Отправитель запроса не нуждается в информации о том, какой объект обработает запрос, что снижает связанность и упрощает код.
Рассмотрим пример, где запросы обрабатываются различными уровнями поддержки (например, базовая, средняя и расширенная поддержка).
from abc import ABC, abstractmethod
class Handler(ABC):
def __init__(self, successor=None):
self._successor = successor
@abstractmethod
def handle(self, request):
if self._successor:
return self._successor.handle(request)
return None
class BasicSupportHandler(Handler):
def handle(self, request):
if request == 'basic':
return "Basic support handled the request"
return super().handle(request)
class IntermediateSupportHandler(Handler):
def handle(self, request):
if request == 'intermediate':
return "Intermediate support handled the request"
return super().handle(request)
class AdvancedSupportHandler(Handler):
def handle(self, request):
if request == 'advanced':
return "Advanced support handled the request"
return super().handle(request)
# Создаем цепочку обработчиков
handler_chain = BasicSupportHandler(
IntermediateSupportHandler(
AdvancedSupportHandler()
)
)
# Тестируем цепочку
print(handler_chain.handle('basic')) # Basic support handled the request
print(handler_chain.handle('intermediate')) # Intermediate support handled the request
print(handler_chain.handle('advanced')) # Advanced support handled the request
print(handler_chain.handle('unknown')) # None (запрос не обработан)
Все конкретные обработчики наследуются от него и реализуют метод
handle
.Каждый обработчик проверяет, может ли он обработать запрос. Если может, он обрабатывает его и возвращает результат. Если не может, он передает запрос следующему обработчику в цепочке.
Обработчики связываются друг с другом, образуя цепочку.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤1
Anonymous Quiz
65%
next() возвращает следующий элемент итератора и вызывается без аргументов
28%
next() возвращает следующий элемент итератора и может принимать значение по умолчанию
2%
next() используется для преобразования списка в итератор
5%
next() изменяет итератор и возвращает его
👍6❤1
Паттерн Команда (Command) — это поведенческий паттерн проектирования, который превращает запросы в объекты, позволяя передавать их как аргументы при вызове методов, ставить запросы в очередь, логировать их и поддерживать отмену операций. Этот паттерн инкапсулирует запрос в виде объекта, что позволяет легко манипулировать действиями, включая отмену и повторное выполнение.
Отделяет объект, инициирующий запрос, от объекта, выполняющего запрос.
Позволяет реализовать операции отмены и повтора действий, так как команды хранят состояние для выполнения и отмены.
Легко логировать команды и добавлять их в очередь для последовательного выполнения.
Уменьшает связанность между отправителем и получателем запроса, делая систему более гибкой.
Рассмотрим пример реализации паттерна Команда для управления светом (включение и выключение).
from abc import ABC, abstractmethod
# Интерфейс команды
class Command(ABC):
@abstractmethod
def execute(self):
pass
@abstractmethod
def undo(self):
pass
# Получатель команды
class Light:
def on(self):
print("Light is ON")
def off(self):
print("Light is OFF")
# Конкретная команда для включения света
class LightOnCommand(Command):
def __init__(self, light: Light):
self._light = light
def execute(self):
self._light.on()
def undo(self):
self._light.off()
# Конкретная команда для выключения света
class LightOffCommand(Command):
def __init__(self, light: Light):
self._light = light
def execute(self):
self._light.off()
def undo(self):
self._light.on()
# Инициатор команды
class RemoteControl:
def __init__(self):
self._command = None
def set_command(self, command: Command):
self._command = command
def press_button(self):
if self._command:
self._command.execute()
def press_undo(self):
if self._command:
self._command.undo()
# Использование паттерна Команда
light = Light()
light_on_command = LightOnCommand(light)
light_off_command = LightOffCommand(light)
remote = RemoteControl()
# Включаем свет
remote.set_command(light_on_command)
remote.press_button() # Light is ON
remote.press_undo() # Light is OFF
# Выключаем свет
remote.set_command(light_off_command)
remote.press_button() # Light is OFF
remote.press_undo() # Light is ON
Объявляет методы
execute
и undo
, которые должны реализовать конкретные команды.Реализуют интерфейс
Command
и определяют, как выполнять и отменять действия.Объект, который выполняет действия (в данном случае, включение и выключение света).
Объект, который вызывает команды. Он не знает, что именно делает команда, а просто вызывает её методы
execute
и undo
.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8