← Назад к вопросам

Что такое MVVM паттерн в Python?

2.0 Middle🔥 131 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

MVVM паттерн в Python

MVVM (Model-View-ViewModel) — это **архитектурный паттерн**, который отделяет пользовательский интерфейс от бизнес-логики приложения. Паттерн широко используется в лесном приложении, особенно в фреймворках с привязкой данных (data binding), таких как WPF, Xamarin и Angular. В Python MVVM применяется реже, чем MVC или MVP, но используется в desktop и некоторых web приложениях.

Компоненты MVVM

Model — содержит бизнес-логику и доступ к данным. Это самостоятельный слой, не знающий о существовании View или ViewModel:

class User:
    def __init__(self, name: str, email: str):
        self.name = name
        self.email = email
    
    def validate_email(self) -> bool:
        return "@" in self.email

class UserRepository:
    def get_user(self, user_id: int) -> User:
        # Получаем пользователя из БД
        pass
    
    def save_user(self, user: User) -> None:
        # Сохраняем пользователя в БД
        pass

View — отвечает только за визуализацию данных. View не содержит бизнес-логики, только отображение. View знает о ViewModel и подписывается на его изменения:

from tkinter import Tk, Label, Entry, Button

class UserView:
    def __init__(self, root: Tk):
        self.root = root
        self.name_label = Label(root, text="Name:")
        self.name_entry = Entry(root)
        self.email_label = Label(root, text="Email:")
        self.email_entry = Entry(root)
        self.save_button = Button(root, text="Save")
        
        self.name_label.pack()
        self.name_entry.pack()
        self.email_label.pack()
        self.email_entry.pack()
        self.save_button.pack()
    
    def set_view_model(self, view_model: 'UserViewModel') -> None:
        self.view_model = view_model
        self.save_button.config(command=view_model.save_user)
        # Подписываемся на изменения в ViewModel
        view_model.on_user_loaded += self.display_user
    
    def display_user(self, user: User) -> None:
        self.name_entry.delete(0, "end")
        self.name_entry.insert(0, user.name)
        self.email_entry.delete(0, "end")
        self.email_entry.insert(0, user.email)

ViewModel — связующий слой между View и Model. ViewModel содержит логику представления, подготавливает данные для View и обрабатывает команды от пользователя. Это реактивный объект, который отправляет уведомления об изменениях:

from typing import Callable, List

class UserViewModel:
    def __init__(self, repository: UserRepository):
        self.repository = repository
        self._user: User = None
        self.on_user_loaded: List[Callable] = []
        self.on_loading_changed: List[Callable] = []
    
    @property
    def user(self) -> User:
        return self._user
    
    @user.setter
    def user(self, value: User) -> None:
        self._user = value
        # Уведомляем все подписчиков об изменении
        for callback in self.on_user_loaded:
            callback(value)
    
    def load_user(self, user_id: int) -> None:
        # Уведомляем об начале загрузки
        for callback in self.on_loading_changed:
            callback(True)
        
        # Загружаем данные через Model
        loaded_user = self.repository.get_user(user_id)
        self.user = loaded_user
        
        # Уведомляем об окончании загрузки
        for callback in self.on_loading_changed:
            callback(False)
    
    def save_user(self) -> None:
        if self._user and self._user.validate_email():
            self.repository.save_user(self._user)
        else:
            raise ValueError("Invalid user data")

Использование с привязкой данных

В Python для реализации двусторонней привязки данных можно использовать библиотеку dataclasses с properties или специализированные фреймворки:

from dataclasses import dataclass
from typing import Callable, Any

class Observable:
    def __init__(self):
        self._value = None
        self._observers: List[Callable] = []
    
    @property
    def value(self):
        return self._value
    
    @value.setter
    def value(self, new_value: Any):
        if self._value != new_value:
            self._value = new_value
            self._notify_observers()
    
    def subscribe(self, observer: Callable) -> None:
        self._observers.append(observer)
    
    def _notify_observers(self) -> None:
        for observer in self._observers:
            observer(self._value)

class UserViewModel:
    def __init__(self, repository: UserRepository):
        self.repository = repository
        self.user_name = Observable()
        self.user_email = Observable()
        self.is_loading = Observable()

Преимущества MVVM

  1. Разделение ответственности — View, ViewModel и Model имеют чёткие границы
  2. Тестируемость — ViewModel можно тестировать отдельно без UI
  3. Переиспользование — один ViewModel может использоваться несколькими View
  4. Привязка данных — двусторонняя синхронизация автоматична
  5. Масштабируемость — удобно для больших приложений

Недостатки MVVM

  1. Сложность — требует больше boilerplate кода
  2. Избыточность для малых проектов — паттерн может быть overkill
  3. Кривая обучения — нужно понимать реактивное программирование

MVVM в Python фреймворках

PyQt/PySide — популярное использование MVVM для desktop приложений

from PyQt5.QtCore import pyqtSignal, QObject

class UserViewModel(QObject):
    user_changed = pyqtSignal(User)
    
    def __init__(self):
        super().__init__()
        self._user = None
    
    @property
    def user(self):
        return self._user
    
    @user.setter
    def user(self, value):
        self._user = value
        self.user_changed.emit(value)

MVVM — это мощный паттерн для разработки приложений с богатым пользовательским интерфейсом и сложной бизнес-логикой.