Наблюдатель (observer)
Определение: паттерн наблюдатель определяет отношение «один ко многим» между объектами таким образом, что при измении состояния одного объекта происходит автоматическое оповещение и обновление всех зависимых объектов.
Простыми словами: у нас есть класс, у которого какие‑то параметры меняются со временем. Наблюдатели — объекты, которые каждый раз получают уведомление, когда у класса меняется какой‑то параметр.
Пример: рассмотрим ситуацию, когда у нас есть пациент у которого нужно отслеживать температуру и пульс и отправлять информацию на основе полученных данных. Пациент — наш класс, у которого со временем меняются параметры (температура и пульс). Наблюдатели — блоки кода, которые выводят информацию в те моменты, когда меняются параметры.
class AbstractClass:
    """
        Абстрактный класс, у которого определены три функции:
        add_obs - добавить наблюдателя
        remove_obs - удалить наблюдателя
        notify_observer - разослать уведомления наблюдателям
    """
    def __init__(self):
        self.__observers = []
    def add_obs(self, observer):
        self.__observers.append(observer)
    def remove_obs(self, observer):
        self.__observers.remove(observer)
    def notify_observer(self, *arg):
        for i in self.__observers:
            i.update(self, *arg)class AbstractObserver:
    """
        Абстрактный наблюдатель от которого нужно будет наследоваться конкретным
        наблюдателям и переопределять метод update, который 
    """
    def __init__(self):
        pass
    def update(self):
        passclass Patient(AbstractClass):
    """
        Конкретный пациент - который в случае изменения параметров вызывает
        функция notify_observer
    """
    def __init__(self, name):
        super().__init__()
        self.name = name
        self.params = {"temperature": 0.0, "heartrate": 0.0}
    def set_value(self, measure_type, val):
        if measure_type in self.params:
            self.params[measure_type] = val
            self.notify_observer()
        else:
            print("Такого параметра нет")
    def get_value(self, measure_type):
        if measure_type in self.params:
            return self.params[measure_type]
        else:
            return Noneclass HeartbeatMonitor(AbstractObserver):
    """
        Конкретный наблюдатель пульса - в зависимости от значения пульса
        выводит результат 
    """
    def __init__(self):
        super().__init__()
    def update(self, tt):
        if type(tt).__name__ == 'Patient':
            hr = tt.get_value("heartrate")
            if hr > 120:
                print("Пульс слишком быстрый: " + str(hr))
            elif hr < 35:
                print("Пульс слишком медленный:  " + str(hr))
            else:
                print("Пульс в норме: " + str(hr))
        else:
            pass
class Thermometer(AbstractObserver):
    """
        Конкретный наблюдатель температуры - в зависимости от значения температуры
        выводит результат
    """
    def __init__(self):
        super().__init__()
    def update(self, tt):
        if type(tt).__name__ == 'Patient':
            temp = tt.get_value("temperature")
            if temp > 37.8:
                print("Слишком высокая температура: " + str(temp))
            elif temp < 35.0:
                print("Слишком низкая температура: " + str(temp))
            else:
                print("Температура в норме: " + str(temp))
        else:
            passimport time
if __name__ == "__main__":
    sub = Patient("Кирилл")
    obs1 = Thermometer()
    obs2 = HeartbeatMonitor()
    for i in range(15):
        time.sleep(1)
        print("====== Шаг {} =======".format(i + 1))
        if i == 3:
            sub.add_obs(obs1) # На третью итерацию добавляем наблюдателя температуры
        elif i == 5:
            sub.add_obs(obs2) # На пятую итерацию добавляем наблюдателя пульса
        elif i == 10:
            sub.remove_obs(obs1) # На десятую итерацию убираем наблюдателя температуры
        if i % 3 == 0:
            sub.set_value("temperature", 35.5 + 0.5 * i)
        elif i % 3 == 1:
            sub.set_value("heartrate", 30 + 10 * i)Результат:

Декоратор (decorator)
Определение: паттерн декоратор динамически наделяет объект новыми возможностями и является гибкой альтернативой субклассированию в области расширения функциональности.
Простыми словами: паттерн позволяет добавлять новый функционал нашему объекту, не изменяя код этого объекта.
Пример: декоратор, который запоминает с какими параметрами уже вызывалась конкретная функция и если такой параметр встретился, то сразу возвращает значение, не вызывая саму функцию (мемоизация).
import sys
def memoize(f):
    cache = dict()
    def wrapper(x):
        if x not in cache:
            cache[x] = f(x)
        return cache[x]
    return wrapper
@memoize
def fib(n):
    if n <= 1:
        return n
    else:
        return fib(n - 1) + fib(n - 2)
if __name__ == "__main__":
    sys.setrecursionlimit(2000)
    print(fib(750))Результат:

Абстрактная фабрика (abstract factory)
Определение: паттерн предоставляет интерфейс создания семейств взаимосвязанных или взаимозависимых объектов без указания их конкретных классов.
Простыми словами: позволяет отделить логику создания объектов от логики их использования. Предоставляет интерфейс создания семейств связанных или зависимых объектов, не специфицируя их конкретные классы.
Пример: создание элементов пользовательского интерфейса для разных операционных систем.
class Button:
    def draw(self):
        raise NotImplementedError
class Checkbox:
    def draw(self):
        raise NotImplementedError
class WindowsButton(Button):
    def draw(self):
        return "Drawing a Windows Button"
class WindowsCheckbox(Checkbox):
    def draw(self):
        return "Drawing a Windows Checkbox"
class MacOSButton(Button):
    def draw(self):
        return "Drawing a MacOS Button"
class MacOSCheckbox(Checkbox):
    def draw(self):
        return "Drawing a MacOS Checkbox"
class GUIFactory:
    def create_button(self):
        raise NotImplementedError
    def create_checkbox(self):
        raise NotImplementedError
class WindowsGUIFactory(GUIFactory):
    def create_button(self):
        return WindowsButton()
    def create_checkbox(self):
        return WindowsCheckbox()
class MacOSGUIFactory(GUIFactory):
    def create_button(self):
        return MacOSButton()
    def create_checkbox(self):
        return MacOSCheckbox()
def create_ui(factory):
    button = factory.create_button()
    checkbox = factory.create_checkbox()
    return button.draw(), checkbox.draw()
if __name__ == "__main__":
    windows_factory = WindowsGUIFactory()
    windows_button, windows_checkbox = create_ui(windows_factory)
    print(f"Windows UI: {windows_button}, {windows_checkbox}")
    macos_factory = MacOSGUIFactory()
    macos_button, macos_checkbox = create_ui(macos_factory)
    print(f"MacOS UI: {macos_button}, {macos_checkbox}")
Результат:

Фабричный метод (factory method)
Определение: паттерн определяет интерфейс создания объекта, но позволяет субклассам выбрать класс создаваемого экземпляра. Таким образом, фабричный метод делегирует операцию создания экземпляра субклассам.
Простыми словами: Используется для создания отдельных объектов с гибким выбором реализации тогда, когда нужно делегировать логику выбора конкретного класса для создания одиночного объекта подклассам.
Пример: создание разных типов документов.
class Document:
    def __init__(self, content):
        self.content = content
    def render(self):
        raise NotImplementedError("Subclasses must implement this method")
class PDFDocument(Document):
    def render(self):
        return f"Rendering PDF Document: {self.content}"
class HTMLDocument(Document):
    def render(self):
        return f"Rendering HTML Document: {self.content}"
class DocumentCreator:
    def create_document(self, content):
        raise NotImplementedError("Subclasses must implement this method")
    def display_document(self, content):
        document = self.create_document(content)
        print(document.render())
class PDFDocumentCreator(DocumentCreator):
    def create_document(self, content):
        return PDFDocument(content)
class HTMLDocumentCreator(DocumentCreator):
    def create_document(self, content):
        return HTMLDocument(content)
if __name__ == "__main__":
    pdf_creator = PDFDocumentCreator()
    pdf_creator.display_document("This is a PDF document")
    html_creator = HTMLDocumentCreator()
    html_creator.display_document("This is an HTML document")
Результат:

Одиночка (singleton)
Определение: паттерн гарантирует, что класс имеет только один экземпляр, и предоставляет глобальную точку доступа к этому экземпляру.
Простыми словами: как бы вы не хотели, не получится создать больше одного экземпляра класса.
Пример:
class SingletonClass:
    _instance = None 
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super(SingletonClass, cls).__new__(cls)
        return cls._instance
singleton = SingletonClass()
new_singleton = SingletonClass()
print(singleton is new_singleton)
singleton.singl_variable = "2"
print(new_singleton.singl_variable)Результат:

Команда (command)
Определение: паттерн инкапсулирует запрос в виде объекта, делая возможной параметризацию клиентских объектов с другими запросами, организацию очереди или регистрацию запросов, а также поддержку отмены операции.
Простыми словами: позволяет отделить то, что нужно сделать, от того, как это сделать.
Пример: включение/выключение света.
from abc import ABC, abstractmethod
class Command(ABC):
    @abstractmethod
    def execute(self):
        pass
class Light:
    def turn_on(self):
        print("The light is ON")
    def turn_off(self):
        print("The light is OFF")
class TurnOnCommand(Command):
    def __init__(self, light):
        self.light = light
    def execute(self):
        self.light.turn_on()
class TurnOffCommand(Command):
    def __init__(self, light):
        self.light = light
    def execute(self):
        self.light.turn_off()
class RemoteControl:
    def __init__(self):
        self.command = None
    def set_command(self, command):
        self.command = command
    def press_button(self):
        if self.command:
            self.command.execute()
if __name__ == "__main__":
    light = Light()
    remote = RemoteControl()
    turn_on = TurnOnCommand(light)
    turn_off = TurnOffCommand(light)
    remote.set_command(turn_on)
    remote.press_button()
    remote.set_command(turn_off)
    remote.press_button()
Результат:

Адаптер (adapter)
Определение: паттерн преобразует интерфейс класса к другому интерфейсу, на который рассчитан клиент. Адаптер обеспечивает совместную работу классов, невозможную в обычных условиях из-за несовместимости интерфейсов.
Простыми словами: Позволяет классам с несовместимыми интерфейсами работать вместе. Выступает в роли переводчика, преобразуя интерфейс одного класса в интерфейс, который ожидает другой класс.
Пример:
# Интерфейс, который ожидает клиент
class NotificationService:
    def send_notification(self, message, recipient):
        raise NotImplementedError("Subclasses must implement this method")
# Класс, который нужно адаптировать
class LegacyNotificationSystem:
    def send_legacy_notification(self, user_id, text):
        print(f"Legacy system: Sending notification '{text}' to user {user_id}")
# Адаптер
class NotificationAdapter(NotificationService):
    def __init__(self, legacy_system):
        self.legacy_system = legacy_system
    def send_notification(self, message, recipient):
        # Преобразуем данные в формат, понятный для LegacyNotificationSystem
        self.legacy_system.send_legacy_notification(recipient, message)
class Client:
    def __init__(self, notification_service):
        self.notification_service = notification_service
    def send_message(self, message, recipient):
        self.notification_service.send_notification(message, recipient)
if __name__ == "__main__":
    legacy_system = LegacyNotificationSystem()
    adapter = NotificationAdapter(legacy_system)
    client = Client(adapter)
    client.send_message("Hello, world!", "12345")
Результат:

Фасад (facade)
Определение: паттерн предоставляет унифицированный интерфейс к группе интерфейсов подсистемы.Он определяет высокоуровневый интерфейс, упрощающий работу с подсистемой.
Простыми словами: предоставляет упрощённый интерфейс к сложной системе, скрывает сложность системы и предоставляет клиенту более удобный и простой способ взаимодействия с ней.
Пример: вместо того, чтобы пользователю по-отдельности пользоваться классам Inventory, Payment и Notification был собран один класс OrderFacade, с которым намного проще обращаться.
class Inventory:
    def check_stock(self, product_id):
        print(f"Checking stock for product {product_id}")
        return True
    def update_stock(self, product_id, quantity):
        print(f"Updating stock for product {product_id} by {quantity}")
class Payment:
    def process_payment(self, amount):
        print(f"Processing payment of ${amount}")
        return True
class Notification:
    def send_confirmation(self, order_id):
        print(f"Sending confirmation for order {order_id}")
class OrderFacade:
    def __init__(self):
        self.inventory = Inventory()
        self.payment = Payment()
        self.notification = Notification()
    def place_order(self, product_id, quantity, amount):
        if self.inventory.check_stock(product_id):
            if self.payment.process_payment(amount):
                self.inventory.update_stock(product_id, -quantity)
                self.notification.send_confirmation(product_id)
                print("Order placed successfully")
            else:
                print("Payment processing failed")
        else:
            print("Product is out of stock")
if __name__ == "__main__":
    facade = OrderFacade()
    facade.place_order(product_id=1, quantity=1, amount=100)
Результат:

Шаблонный метод (template method)
Определение: паттерн задаёт скелет алгоритма в методе, оставляя определение реализации некоторых шагов субклассам. Субклассы могут переопределять некоторые части алгоритма без изменения его структуры.
Простыми словами: создаём абстрактный класс, в котором определяем основные шаги алгоритма, например, порядок выполнения функций. При этом позволяя подклассам переопределять эти функции, не меняя его структуру.
Пример:
class ReportGenerator: 
    def generate_report(self):
        self.collect_data()
        self.format_data()
        self.generate_header()
        self.generate_body()
        self.generate_footer()
        self.output_report()
    def collect_data(self):
        raise NotImplementedError("Subclasses must implement this method")
    def format_data(self):
        raise NotImplementedError("Subclasses must implement this method")
    def generate_header(self):
        print("Generating default header")
    def generate_footer(self):
        print("Generating default footer")
    def output_report(self):
        print("Outputting report to console")
class SalesReportGenerator(ReportGenerator):  # ConcreteClass
    def collect_data(self):
        print("Collecting sales data")
        self.sales_data = ["Sales 1", "Sales 2", "Sales 3"]
    def format_data(self):
        print("Formatting sales data")
        self.formatted_sales_data = "\n".join(self.sales_data)
    def generate_header(self):
        print("Generating Sales Report Header")
    def generate_body(self):
        print("Generating Sales Report Body")
        print(self.formatted_sales_data)
class PerformanceReportGenerator(ReportGenerator):  # ConcreteClass
    def collect_data(self):
        print("Collecting performance data")
        self.performance_data = ["Perf 1", "Perf 2", "Perf 3"]
    def format_data(self):
        print("Formatting performance data for web output")
        self.formatted_performance_data = "<br>".join(self.performance_data)
    def generate_body(self):
        print("Generating Performance Report Body")
        print(self.formatted_performance_data)
    def output_report(self):
        print("Outputting report to web page")
if __name__ == "__main__":
    sales_report = SalesReportGenerator()
    sales_report.generate_report()
    performance_report = PerformanceReportGenerator()
    performance_report.generate_report()
Результат:

Итератор (iterator)
Определение: паттерн предоставляет механизм последовательного перебора элементов коллекции без раскрытия её внутреннего представления.
Простыми словами: используется для того, чтобы последовательно перебирать элементы коллекции не зная как они хранятся в памяти.
Пример:
class NumberIterator:
    def __init__(self, numbers):
        self._numbers = numbers
        self._index = 0
    def __iter__(self):
        return self
    def __next__(self):
        if self._index < len(self._numbers):
            result = self._numbers[self._index]
            self._index += 1
            return result
        else:
            raise StopIteration
numbers = [1, 2, 3, 4, 5]
iterator = NumberIterator(numbers)
for number in iterator:
    print(number)
Результат:

Компоновщик (composite)
Определение: паттерн объединяет объекты в древовидные структуры для представления иерархий «часть/целое». Позволяет клиенту выполнять однородные операции с отдельными объектами и их совокупностями.
Простыми словами: позволяет объединять объекты в древовидные структуры и работать с ними как с единым целым, так и по‑отдельности.
Пример: файловая система.
from abc import ABC, abstractmethod
class FileSystem(ABC):
    @abstractmethod
    def print(self, indent: int = 0) -> None:
        pass
class File(FileSystem):
    def __init__(self, name: str, size: int):
        self.name = name
        self.size = size
    def print(self, indent: int = 0) -> None:
        print(" " * indent + f"Файл: {self.name} (Размер: {self.size} KB)")class Directory(FileSystem):
    def __init__(self, name: str):
        self.name = name
        self.contents: list = []
    def print(self, indent: int = 0) -> None:
        print(" " * indent + f"Папка: {self.name}")
        for entity in self.contents:
            entity.print(indent + 2)
    def add_entity(self, entity: FileSystem) -> None:
        self.contents.append(entity)
    def remove_entity(self, entity: FileSystem) -> None:
        if entity in self.contents:
            self.contents.remove(entity)def main():
    file1 = File("file1.txt", 128)
    file2 = File("file2.txt", 1024)
    file3 = File("file3.txt", 2048)
    dir1 = Directory("dir1")
    dir1.add_entity(file1)
    dir1.add_entity(file2)
    nested_dir = Directory("nested_dir")
    nested_dir.add_entity(file3)
    dir1.add_entity(nested_dir)
    root_dir = Directory("root")
    root_dir.add_entity(dir1)
    root_dir.add_entity(File("root_file.txt", 256))
    root_dir.print()
if __name__ == "__main__":
    main()
Результат:

Состояние (state)
Определение: паттерн управляет изменением поведения объекта при изменении его внутреннего состояния. Внешне это выглядит так, словно объект меняет свой класс.
Простыми словами: паттерн реализует структуру, в которой при изменении какого-то параметра объекта меняется то, как он будет обрабатывать поступающие в него запросы.
Пример: работа лифта у которого есть два состояния: первый этаж, второй этаж.
from __future__ import annotations
from abc import ABC, abstractmethod
class Elevator:
    _state = None
    def __init__(self, state: State) -> None:
        self.setElevator(state)
    def setElevator(self, state: State):
        self._state = state
        self._state.elevator = self
    def presentState(self):
        print(f"Лифт на {type(self._state).__name__}")
    def pushDownBtn(self):
        self._state.pushDownBtn()
    def pushUpBtn(self):
        self._state.pushUpBtn()
class State(ABC):
    def __init__(self):
        self._elevator = None
    @property
    def elevator(self) -> Elevator:
        return self._elevator
    @elevator.setter
    def elevator(self, elevator: Elevator) -> None:
        self._elevator = elevator
    @abstractmethod
    def pushDownBtn(self) -> None:
        pass
    @abstractmethod
    def pushUpBtn(self) -> None:
        pass
class FirstFloor(State):
    def pushDownBtn(self) -> None:
        print("Уже на первом этаже")
    def pushUpBtn(self) -> None:
        print("Лифт поднимается на второй этаж")
        self.elevator.setElevator(SecondFloor())
class SecondFloor(State):
    def pushDownBtn(self) -> None:
        print("Лифт опускается на первый этаж")
        self.elevator.setElevator(FirstFloor())
    def pushUpBtn(self) -> None:
        print("Лифт уже на втором этаже")
if __name__ == "__main__":
    myElevator = Elevator(FirstFloor())
    myElevator.presentState()
    myElevator.pushUpBtn()
    myElevator.presentState()
    myElevator.pushDownBtn()
    myElevator.presentState()
Результат:

Заместитель (proxy)
Определение: паттерн предоставляет суррогатный объект, управляющий доступом к другому объекту.
Простыми словами: заместитель позволяет управлять доступом к объекту не изменяя сам объект.
Пример: отложенная загрузка изображения.
class Image:
    def __init__(self, filename):
        self.filename = filename
        self.image = None  # Изображение еще не загружено
    def display(self):
        raise NotImplementedError
class RealImage(Image):
    def __init__(self, filename):
        super().__init__(filename)
        self.load_from_disk()  # Загрузка сразу при создании
    def load_from_disk(self):
        print(f"Загружаю {self.filename} с диска...")
        self.image = f"информация о {self.filename}"
        print(f"Картинка {self.filename} загружена.")
    def display(self):
        print(f"Отображена {self.image}")
class ProxyImage(Image):
    def __init__(self, filename):
        super().__init__(filename)
        self.real_image = None  # Реальное изображение еще не создано
    def display(self):
        if self.real_image is None:
            self.real_image = RealImage(self.filename)  # Загружаем только при необходимости
        self.real_image.display()
if __name__ == "__main__":
    image1 = ProxyImage("image1.jpg")
    image2 = ProxyImage("image2.png")
    print("Картинки ещё не созданы")
    image1.display()  # Вот тут произойдет загрузка image1
    image2.display()  # Вот тут произойдет загрузка image2
    Результат:

Комментарии (11)
 - Dhwtj22.07.2025 18:05- В реальных проектах на Python востребованность паттернов GoF сильно ниже, чем в Java/C# ввиду иных решаемых задач/проектов. Многие из них либо встроены в язык, либо решаются проще - 3 паттерна встроены в язык: - Декоратор 
- Итератор 
- Синглтон 
 - Многие паттерны реализуются через ФП: - Стратегия = передача функции как параметр 
- Фабричный метод = функция, которая возвращает экземпляр нужного класса 
 - А не вот это вот всё... 
 - TimurZhoraev22.07.2025 18:05- Можно ещё добавить магическую команду exec как шаблон кодогенерации. Например, в начале скрипта проинициализировать некие статические счётчики для отладки - A, N = "", 40 for i in range(N): if i < (N - 1): #неявный else A = A + ("CTR"+str(i)+"=1"+';') + ("DBGL"+str(i)+"=0"+';') exec(A) - Dhwtj22.07.2025 18:05- exec это же дыра в безопасности, особенно если выполнять то что пришло параметром в функцию.  - TimurZhoraev22.07.2025 18:05- Вот, это ключевой момент который в принципе тормозит весь прогресс из разряда "данные это код" Since 1958 by LISP. ИИ-помощник не меньшая дыра если не следить, туда же внешние макросы и прочие make, куда можно прилинковать напрямую любой код, качнув его по wget. Это что касается этапа построения. Что же до рантайма то должны быть способы для создания подобия песочниц-контейнеров прямо в коде. Начиная от специальных областей памяти для ввода паролей с солью и заканчивая VM содержащей только окружение и область для временных объектов, вообщем malloc, но для кода. 
 В принципе, формально, функция есть нечто иное как изменение области видимости с сохранением окружения (call), если нет стека - то это процедура (jmp) и в качестве аргумента также может быть исполняемый код как указатель на функцию или адрес перехода. На С можно сделать аналог функции не применяя саму функцию. Например a - это аргумент и локальная переменная (как правило, размещаемая в стеке или регистре {} - область видимости)- /*"Лямбда"*/ { int a=0; goto sub; ret: goto bypass; { sub: int a=1; goto ret; } bypass: }
 
 
 - nickolaym22.07.2025 18:05- Ещё одна статья галопом-по-европам с оторванными онт жизни примерами GoF вперемешку с чисто питоньими штуками. - Почему декоратор проиллюстрирован питоньим декоратором, а не вот этими всеми абстрактными классами... А фабрика - наоборот, по-явовски, вместо того, чтобы натрюкачить с метаклассом? - Если задача автора была показать паттерны - то надо было перевести примеры из GoF на питон, как есть. Если показать питон - то надо было объяснять, какие вещи в питоне делаются с поддержкой ядра языка (те же итераторы, например), а какие придётся рукоделить. - А главное, - зачем вообще надо эти паттерны воплощать. - Вот, например, итератор - это жизненная необходимость для любых коллекций, чтобы доступ к ним был унифицирован (синтаксис for и стандартная библиотека - min, map, itertools и всё такое). То есть, это требование языка, а не требование архитектуры приложения или предметной области. - И то, - с одной стороны, последовательный доступ, а с другой - прямой (по ключу или индексу). Почему не проиллюстрировано, а? 
 - dan_sw22.07.2025 18:05- Что в Вашей статье есть принципиально нового? Кроме простых примеров, которые немного демонстрируют работу и поведение паттернов, хорошо описанных на куче разных других ресурсах (на данном ресурсе в том числе). На мой взгляд - вообще ничего нового. Темы эти поднимались уже кучу раз и где только о паттернах нельзя сейчас почитать. - Рекомендую ознакомится с сайтом, с которого Вы взяли картинку для данной статьи, в которой все эти паттерны очень хорошо и структурно описаны, разобраны донельзя и предложен необходимый фундамент для их использования: Refactoring Guru 
 - Xiran22.07.2025 18:05- Прочитав название статьи "Фундаментальные шаблоны проектирования на Python" я ожидал увидеть что-то чисто питоновское, типа паттерны, принятые только в сообществе питона, этот самый Pythonic-way. Но тут увидел какие-то общие паттерны ООП, при том часть из них, как уже написали встроены в язык. И реализация многих не сильно Pythonic. Нужно было назвать типа "Описание паттернов ООП и примеры их реализации на Python" 
 - upcFrost22.07.2025 18:05- "Как сделать из пистона жабу, пособие для начинающих". Не, я одобряю, если что 
 
           
 
izibrizi2
Ох, ну зачем в питоне программировать на джаве? Декоратор и итератор - это вообще не в ту калитку. Половина паттернов расчитана на джаву, в которой нельзя объявлять функции без классов, а в питоне эти паттерны иначе выглядят