Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Memento и сериализация
memento

Memento и сериализация

Сохранение состояния объектов. Pickle для сериализации. dataclasses.asdict и __getstate__/__setstate__.

Memento и сериализация

Memento сохраняет момент времени. Pickle сохраняет объекты.


#Memento: сохранение состояния

Memento — поведенческий паттерн, позволяющий сохранять и восстанавливать состояние объекта, не нарушая инкапсуляцию.

#Проблема: нарушение инкапсуляции

# ❌ ПЛОХО: Нарушение инкапсуляции class Editor: def __init__(self): self.text = "" self.cursor = 0 # Клиент знает о внутренностях editor = Editor() editor.text = "Hello" editor.cursor = 5 # Сохранение требует знания структуры saved_state = (editor.text, editor.cursor) # Восстановление editor.text, editor.cursor = saved_state

#Решение 1: Memento через класс

# ✅ ХОРОШО: Инкапсуляция сохранена class Memento: """Хранитель состояния — неизменяемый""" def __init__(self, text: str, cursor: int): self._text = text self._cursor = cursor @property def text(self) -> str: return self._text @property def cursor(self) -> int: return self._cursor class Editor: def __init__(self): self._text = "" self._cursor = 0 def type(self, text: str): self._text = self._text[:self._cursor] + text + self._text[self._cursor:] self._cursor += len(text) @property def text(self) -> str: return self._text def save(self) -> Memento: """Создаёт снимок состояния""" return Memento(self._text, self._cursor) def restore(self, memento: Memento): """Восстанавливает состояние""" self._text = memento.text self._cursor = memento.cursor # Использование editor = Editor() editor.type("Hello") editor.type(" World") # Сохранение saved = editor.save() editor.type("!") print(editor.text) # Hello World! # Восстановление editor.restore(saved) print(editor.text) # Hello World

#Решение 2: Memento через dict

# ✅ Проще: Memento как словарь from typing import Dict, Any class Editor: def __init__(self): self._state: Dict[str, Any] = {"text": "", "cursor": 0} def type(self, text: str): cursor = self._state["cursor"] self._state["text"] = ( self._state["text"][:cursor] + text + self._state["text"][cursor:] ) self._state["cursor"] = cursor + len(text) def save(self) -> Dict[str, Any]: return self._state.copy() def restore(self, state: Dict[str, Any]): self._state = state.copy() # Использование editor = Editor() editor.type("Hello") saved = editor.save() editor.type(" World") editor.restore(saved)

#Undo/Redo через Memento

# ✅ История снимков from typing import List class EditorWithHistory: def __init__(self): self._text = "" self._cursor = 0 self._history: List[Memento] = [] self._redo_stack: List[Memento] = [] def type(self, text: str): self.save() # Сохраняем перед изменением cursor = self._cursor self._text = self._text[:cursor] + text + self._text[cursor:] self._cursor = cursor + len(text) self._redo_stack.clear() # Сброс redo def save(self): self._history.append(Memento(self._text, self._cursor)) def undo(self): if len(self._history) > 1: self._redo_stack.append(self._history.pop()) self.restore(self._history[-1]) def redo(self): if self._redo_stack: self.save() self.restore(self._redo_stack.pop()) @property def text(self) -> str: return self._text def restore(self, memento: Memento): self._text = memento.text self._cursor = memento.cursor # Использование editor = EditorWithHistory() editor.type("Hello") editor.type(" World") editor.type("!") editor.undo() # "Hello World" editor.undo() # "Hello" editor.redo() # "Hello World"

#Pickle: сериализация объектов

#Базовая сериализация

# ✅ Pickle для сохранения объектов import pickle class GameState: def __init__(self): self.player_name = "Hero" self.level = 1 self.health = 100 self.inventory = ["sword", "shield"] # Сохранение state = GameState() with open("save.pkl", "wb") as f: pickle.dump(state, f) # Загрузка with open("save.pkl", "rb") as f: loaded = pickle.load(f) print(loaded.player_name) # Hero

#Pickle с кастомизацией

# ✅ Кастомная сериализация import pickle class DatabaseConnection: def __init__(self, url: str): self.url = url self._connection = None # Не сериализуется! self._connect() def _connect(self): self._connection = f"Connection({self.url})" def __getstate__(self): """Вызывается при сериализации""" state = self.__dict__.copy() # Не сериализуем соединение del state["_connection"] return state def __setstate__(self, state): """Вызывается при десериализации""" self.__dict__.update(state) # Восстанавливаем соединение self._connect() # Использование db = DatabaseConnection("postgresql://localhost") pickled = pickle.dumps(db) restored = pickle.loads(pickled) print(restored.url) # postgresql://localhost

#dataclasses.asdict для Memento

# ✅ dataclasses для снимков from dataclasses import dataclass, asdict from typing import Dict @dataclass class EditorState: text: str = "" cursor: int = 0 class Editor: def __init__(self): self._state = EditorState() def type(self, text: str): cursor = self._state.cursor self._state.text = ( self._state.text[:cursor] + text + self._state.text[cursor:] ) self._state.cursor = cursor + len(text) def save(self) -> Dict: return asdict(self._state) def restore(self, state: Dict): self._state = EditorState(**state) # Использование editor = Editor() editor.type("Hello") saved = editor.save() editor.type(" World") editor.restore(saved)

#Практическое применение

#Snapshot для игр

# ✅ Снимки состояния игры import pickle from datetime import datetime @dataclass class GameSnapshot: timestamp: datetime player_pos: tuple player_health: int enemies: list inventory: dict class Game: def __init__(self): self._snapshots = [] self.player_pos = (0, 0) self.player_health = 100 self.enemies = [] self.inventory = {} def save(self): snapshot = GameSnapshot( timestamp=datetime.now(), player_pos=self.player_pos, player_health=self.player_health, enemies=self.enemies.copy(), inventory=self.inventory.copy(), ) self._snapshots.append(snapshot) def load(self, index: int = -1): snapshot = self._snapshots[index] self.player_pos = snapshot.player_pos self.player_health = snapshot.player_health self.enemies = snapshot.enemies self.inventory = snapshot.inventory def save_to_file(self, filename: str): with open(filename, "wb") as f: pickle.dump(self._snapshots, f) def load_from_file(self, filename: str): with open(filename, "rb") as f: self._snapshots = pickle.load(f)

#Transaction log

# ✅ Лог транзакций from typing import List, Callable import json class TransactionLog: def __init__(self): self._log: List[dict] = [] def record(self, operation: str, data: dict): self._log.append({ "operation": operation, "data": data, "timestamp": datetime.now().isoformat(), }) def replay(self, handler: Callable[[str, dict], None]): for entry in self._log: handler(entry["operation"], entry["data"]) def save(self, filename: str): with open(filename, "w") as f: json.dump(self._log, f) def load(self, filename: str): with open(filename) as f: self._log = json.load(f) # Использование log = TransactionLog() log.record("credit", {"account": 123, "amount": 100}) log.record("debit", {"account": 123, "amount": 50}) def replay_handler(op: str, data: dict): print(f"{op}: {data}") log.replay(replay_handler)

#Глубокое копирование vs Memento

# ✅ copy.deepcopy как простой Memento import copy class Editor: def __init__(self): self.text = "" self.cursor = 0 self.styles = {} # Вложенный объект def save(self): return copy.deepcopy(self.__dict__) def restore(self, state): self.__dict__.update(copy.deepcopy(state)) # deepcopy рекурсивно копирует всё, включая вложенные объекты

#Что дальше?

Изучите тему Observer и Pub/Sub для реактивного программирования.

Далее: Observer и Pub/Sub