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

Что такое Ref?

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

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

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

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

Ref (Reference) в Python и разработке

Определение Ref

Ref или Reference — это ссылка на объект в памяти. В Python всё в памяти это объект, и когда вы присваиваете переменную или передаёте в функцию, вы работаете со ссылками на эти объекты.

Ref в Python (основы)

Как работают references в Python

# Создание объекта
original_list = [1, 2, 3]

# Создание ссылки на тот же объект (не копирование!)
reference = original_list

# Обе переменные указывают на ОДИН объект в памяти
reference.append(4)
print(original_list)  # [1, 2, 3, 4] <- изменился исходный!
print(reference)      # [1, 2, 3, 4]

print(id(original_list))  # 140320849201344
print(id(reference))      # 140320849201344 <- один и тот же id!
print(original_list is reference)  # True

Mutable vs Immutable

Именно refs создают проблемы с mutable объектами:

# MUTABLE объекты (списки, словари, объекты)
my_list = [1, 2, 3]
def modify_list(lst):
    lst.append(999)  # Изменяем ИСХОДНЫЙ список

modify_list(my_list)
print(my_list)  # [1, 2, 3, 999] <- исходный изменился!

# IMMUTABLE объекты (строки, числа, кортежи)
my_string = "Hello"
def modify_string(s):
    s = s + " World"  # Создаётся НОВАЯ строка, исходная не меняется

modify_string(my_string)
print(my_string)  # "Hello" <- исходная не изменилась

Проблема: случайное изменение данных

# ❌ ОПАСНО: использование рефа напрямую
class User:
    def __init__(self, name, tags):
        self.name = name
        self.tags = tags  # ССЫЛКА на входящий список!

user_tags = ["admin", "developer"]
user = User("Ivan", user_tags)

user_tags.append("super_admin")  # Меняем исходный список
print(user.tags)  # ['admin', 'developer', 'super_admin']
# ^ Пользователь неожиданно стал super_admin!

# ✅ ПРАВИЛЬНО: копируем данные
class User:
    def __init__(self, name, tags):
        self.name = name
        self.tags = list(tags)  # Копируем список!

user_tags = ["admin", "developer"]
user = User("Ivan", user_tags)

user_tags.append("super_admin")
print(user.tags)  # ['admin', 'developer'] <- исходные данные не повлияли

Управление Refs

import copy

original_data = {
    "user": {"name": "Ivan", "age": 30},
    "tags": ["python", "django"]
}

# 1. Shallow copy (неглубокое копирование)
shallow = copy.copy(original_data)
shallow["user"]["age"] = 99
print(original_data["user"]["age"])  # 99 <- вложенные объекты меняются!

# 2. Deep copy (глубокое копирование)
deep = copy.deepcopy(original_data)
deep["user"]["age"] = 99
print(original_data["user"]["age"])  # 30 <- исходные данные не меняются!

Ref в React (Frontend)

Если вопрос про React Refs (JavaScript/TypeScript), это другой контекст:

// React Ref — это способ получить доступ к DOM элементам или значениям
import { useRef } from 'react';

function TextInput() {
    // Создание ref
    const inputRef = useRef(null);
    
    // Доступ к DOM элементу напрямую
    const focusInput = () => {
        inputRef.current.focus();  // Фокус на input
    };
    
    return (
        <>
            <input ref={inputRef} />
            <button onClick={focusInput}>Фокус</button>
        </>
    );
}

Ref в контексте управления памятью

Утечки памяти из-за Refs

import weakref

class Observer:
    def __init__(self, name):
        self.name = name
    
    def update(self):
        print(f"{self.name} updated")

class Subject:
    def __init__(self):
        self._observers = []  # СИЛЬНЫЕ references
    
    def attach(self, observer):
        self._observers.append(observer)  # Держим сильный ref
    
    def notify(self):
        for obs in self._observers:
            obs.update()

# Проблема: если объект Observer удалён, он всё равно в памяти!
observer = Observer("Logger")
subject = Subject()
subject.attach(observer)

del observer  # Удаляем переменную
# ^ но объект всё ещё в памяти из-за _observers!

# ✅ РЕШЕНИЕ: используем weakref
class SubjectWithWeakref:
    def __init__(self):
        self._observers = []  # СЛАБЫЕ references
    
    def attach(self, observer):
        self._observers.append(weakref.ref(observer))
    
    def notify(self):
        for obs_ref in self._observers:
            obs = obs_ref()  # Получить объект если он ещё существует
            if obs:  # Если объект не удалён
                obs.update()

Ref в контексте ORM (SQLAlchemy)

from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship, Session

class Author(Base):
    __tablename__ = "authors"
    id = Column(Integer, primary_key=True)
    name = Column(String)
    books = relationship("Book", back_populates="author")

class Book(Base):
    __tablename__ = "books"
    id = Column(Integer, primary_key=True)
    title = Column(String)
    author_id = Column(Integer, ForeignKey("authors.id"))  # REF на authors
    author = relationship("Author", back_populates="books")

# Foreign Key — это именно "ref" на другую таблицу
book = session.query(Book).first()
print(book.author.name)  # Доступ через ref

# Проблема: N+1 queries
for book in session.query(Book).all():
    print(book.author.name)  # Каждый book.author вызывает доп. query!

# ✅ Решение: eager loading
from sqlalchemy.orm import joinedload

books = session.query(Book).options(joinedload(Book.author)).all()
for book in books:
    print(book.author.name)  # Всего 1 query вместо N+1

Ref в контексте JSON API

Когда API возвращает ID вместо полного объекта:

# ❌ Неэффективно: полное копирование данных
{
    "id": 1,
    "title": "Post 1",
    "author": {
        "id": 1,
        "name": "Ivan",
        "email": "ivan@example.com",
        "created_at": "2023-01-01T00:00:00Z"
    }
}

# ✅ Лучше: ref на автора (только ID)
{
    "id": 1,
    "title": "Post 1",
    "author_id": 1  # Ref, клиент может запросить автора отдельно
}

# ✅ Или normalize данные
{
    "posts": [
        {"id": 1, "title": "Post 1", "author_id": 1}
    ],
    "authors": [
        {"id": 1, "name": "Ivan", "email": "ivan@example.com"}
    ]
}

Best Practices для работы с Refs

  1. Не изменяйте объекты через refs в функциях — используйте immutable подход
# ❌ Плохо
def process_data(data_list):
    data_list[0] = 999  # Меняем исходный список!

# ✅ Хорошо
def process_data(data_list):
    new_list = data_list.copy()
    new_list[0] = 999
    return new_list
  1. Копируйте mutable объекты при присваивании в экземпляры класса
class Config:
    def __init__(self, settings):
        self.settings = copy.deepcopy(settings)  # Копируем!
  1. Используйте weakref для обработчиков событий
class EventEmitter:
    def __init__(self):
        self._handlers = []  # weakref на обработчики
    
    def on(self, handler):
        self._handlers.append(weakref.ref(handler))
  1. Помните о N+1 queries с ORМ
# Всегда используйте eager loading
users = session.query(User).options(
    joinedload(User.posts),
    joinedload(User.comments)
).all()

Итог

Ref (Reference) — это фундаментальная концепция в программировании:

  • В Python ВСЕ переменные это refs на объекты
  • Mutable объекты опасны при работе с refs
  • Используйте copy.deepcopy() для безопасности
  • В ORM refs это Foreign Keys
  • В API refs это IDs
  • Помните о weakref для предотвращения утечек памяти

Понимание refs критично для написания надёжного Python кода без unexpected мутаций данных.

Что такое Ref? | PrepBro