Комментарии (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
- Не изменяйте объекты через 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
- Копируйте mutable объекты при присваивании в экземпляры класса
class Config:
def __init__(self, settings):
self.settings = copy.deepcopy(settings) # Копируем!
- Используйте weakref для обработчиков событий
class EventEmitter:
def __init__(self):
self._handlers = [] # weakref на обработчики
def on(self, handler):
self._handlers.append(weakref.ref(handler))
- Помните о 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 мутаций данных.