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

Как сделать объект фиксированной длины?

1.0 Junior🔥 131 комментариев
#Python

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

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

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

Вопрос о создании объекта фиксированной длины в Python — это может быть интерпретировано несколькими способами. Рассмотрю все основные подходы, которые используются в Data Science.

1. NumPy массивы фиксированной формы

Наиболее часто в ML/DS нам нужны числовые массивы с фиксированной размерностью:

import numpy as np

# Способ 1: zeros (инициализация нулями)
arr_zeros = np.zeros((3, 4))  # 3x4 матрица нулей
print(f"Форма: {arr_zeros.shape}")
print(f"Размер в памяти: {arr_zeros.nbytes} bytes")

# Способ 2: ones (инициализация единицами)
arr_ones = np.ones((5, 5))

# Способ 3: empty (неинициализированная память, быстрее)
arr_empty = np.empty((100, 100))

# Способ 4: full (заполнение константой)
arr_full = np.full((3, 3), 7.0)

# Способ 5: arange и reshape
arr = np.arange(12).reshape(3, 4)
print(f"\nАрраи с reshape:\n{arr}")

# Важно: изменить форму массива после создания нельзя
# np.resize создаёт НОВЫЙ массив
arr_resized = np.resize(arr, (2, 3))  # Новый массив, не модификация

2. Список фиксированной длины

Если нужен список Python с фиксированным количеством элементов:

# Способ 1: умножение списка
fixed_list = [0] * 10  # Список из 10 нулей
print(f"Длина: {len(fixed_list)}")
fixed_list[0] = 100  # Можно менять значения
# fixed_list.append(1)  # ✓ Но длина не фиксирована! Список растёт

# Способ 2: список со значениями
fixed_list = list(range(5))  # [0, 1, 2, 3, 4]
print(f"Список: {fixed_list}")

# Способ 3: список со значением по умолчанию
fixed_list = [None] * 5  # Для последующего заполнения
for i in range(len(fixed_list)):
    fixed_list[i] = i ** 2  # [0, 1, 4, 9, 16]
print(f"Заполненный: {fixed_list}")

3. Класс FixedArray с len и getitem

Если нужна собственная реализация с истинно фиксированной длиной:

class FixedArray:
    """Массив с фиксированной длиной"""
    
    def __init__(self, size, default_value=0):
        if size <= 0:
            raise ValueError("Размер должен быть положительным")
        self._data = [default_value] * size
        self._size = size
    
    def __len__(self):
        """Возвращает фиксированную длину"""
        return self._size
    
    def __getitem__(self, index):
        """Получить элемент по индексу"""
        if not isinstance(index, int) or index < 0 or index >= self._size:
            raise IndexError(f"Индекс вне диапазона [0, {self._size-1}]")
        return self._data[index]
    
    def __setitem__(self, index, value):
        """Установить элемент по индексу"""
        if not isinstance(index, int) or index < 0 or index >= self._size:
            raise IndexError(f"Индекс вне диапазона [0, {self._size-1}]")
        self._data[index] = value
    
    def __repr__(self):
        return f"FixedArray({self._data})"
    
    def append(self, value):
        """Запретим добавлять элементы"""
        raise TypeError("FixedArray имеет фиксированную длину, append запрещен")
    
    def __iter__(self):
        """Итерация по элементам"""
        return iter(self._data)

# Использование
fixed = FixedArray(5, default_value=0)
print(f"Длина: {len(fixed)}")
print(f"Исходный: {fixed}")

fixed[0] = 100
fixed[4] = 999
print(f"Изменённый: {fixed}")

try:
    fixed.append(10)  # Ошибка!
except TypeError as e:
    print(f"Ошибка: {e}")

try:
    fixed[10] = 5  # Ошибка: индекс вне диапазона
except IndexError as e:
    print(f"Ошибка: {e}")

4. Кортеж (tuple) — истинно неизменяемая структура

Помните, в Python кортежи имеют фиксированную длину и неизменяемы:

# Создаём кортеж фиксированной длины
fixed_tuple = (1, 2, 3, 4, 5)
print(f"Длина кортежа: {len(fixed_tuple)}")
print(f"Элемент 0: {fixed_tuple[0]}")

# Вы не можете изменить элемент
try:
    fixed_tuple[0] = 100  # TypeError: 'tuple' object does not support item assignment
except TypeError as e:
    print(f"Ошибка: {e}")

# Вы не можете добавить элемент
try:
    fixed_tuple.append(6)  # AttributeError: 'tuple' object has no attribute 'append'
except AttributeError as e:
    print(f"Ошибка: {e}")

# Единственный способ — создать новый кортеж
fixed_tuple = fixed_tuple + (6,)  # Создаёт новый кортеж из 6 элементов

5. collections.deque с maxlen

Для скользящего окна или кёша фиксированного размера:

from collections import deque

# deque с maxlen — автоматически удаляет старые элементы
window = deque(maxlen=3)  # Окно размера 3

for i in range(10):
    window.append(i)
    print(f"Шаг {i}: {list(window)}")

# Выход:
# Шаг 0: [0]
# Шаг 1: [0, 1]
# Шаг 2: [0, 1, 2]
# Шаг 3: [1, 2, 3]  <- первый элемент удалился
# Шаг 4: [2, 3, 4]
# ...

6. Для Machine Learning: NumPy с проверкой формы

В ML часто нужно убедиться, что данные имеют правильную форму:

from sklearn.preprocessing import StandardScaler
import numpy as np

class FixedShapeModel:
    """Модель, которая требует фиксированную форму входных данных"""
    
    def __init__(self, n_features):
        self.n_features = n_features
        self.scaler = StandardScaler()
        self.is_fitted = False
    
    def fit(self, X, y):
        """Обучение с проверкой формы"""
        if X.shape[1] != self.n_features:
            raise ValueError(f"Ожидается {self.n_features} признаков, получено {X.shape[1]}")
        self.scaler.fit(X)
        self.is_fitted = True
        return self
    
    def predict(self, X):
        """Предсказание с проверкой формы"""
        if not self.is_fitted:
            raise RuntimeError("Модель не обучена, вызовите fit() сначала")
        
        if X.shape[1] != self.n_features:
            raise ValueError(f"Ожидается {self.n_features} признаков, получено {X.shape[1]}")
        
        return self.scaler.transform(X)

# Использование
X_train = np.random.randn(100, 5)
y_train = np.random.randn(100)

model = FixedShapeModel(n_features=5)
model.fit(X_train, y_train)

# Верно: 5 признаков
X_test = np.random.randn(20, 5)
result = model.predict(X_test)
print(f"Результат формы: {result.shape}")

# Ошибка: неправильное количество признаков
try:
    X_wrong = np.random.randn(20, 3)
    model.predict(X_wrong)
except ValueError as e:
    print(f"Ошибка: {e}")

Выбор метода по использованию

СпособИзменяемоПроизводительностьКогда использовать
listДаМедленноОбщего назначения
tupleНетСреднеКогда нужна неизменяемость
numpy.arrayДаБыстроЧисловые вычисления
deque(maxlen=n)ДаБыстроСкользящие окна, кэши
FixedArrayДаСреднеСтрогое контроль, проверки

Практический совет для Data Scientist

# В 99% случаев используйте NumPy или деку

# Для батчей данных с фиксированным размером:
batch_size = 32
feature_dim = 128

# Способ 1: создать массив и заполнить
batch = np.zeros((batch_size, feature_dim))
for i in range(batch_size):
    batch[i] = get_sample_features(i)

# Способ 2: собрать в список, потом конвертировать
batch_list = [get_sample_features(i) for i in range(batch_size)]
batch = np.array(batch_list)  # Автоматически (batch_size, feature_dim)

# Способ 3: использовать tf.data.Dataset (если TensorFlow)
import tensorflow as tf
dataset = tf.data.Dataset.from_tensor_slices(data).batch(batch_size)
# Батчи имеют фиксированный размер

Основной вывод: фиксированная длина в Python требует либо NumPy, либо собственной реализации с проверками. Встроенные list всегда динамичны.

Как сделать объект фиксированной длины? | PrepBro