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

Может ли Python массив хранить разные типы данных?

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

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

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

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

Может ли Python массив хранить разные типы данных?

Да, Python списки (list) могут хранить элементы разных типов данных одновременно. Это одна из ключевых особенностей Python как динамически типизированного языка. Однако есть важные нюансы для production-кода.

Списки (list) — гетерогенные контейнеры

Базовый пример

# Один список с разными типами
mixed_list = [1, "hello", 3.14, True, None]

for item in mixed_list:
    print(type(item).__name__, item)

# Вывод:
# int 1
# str hello
# float 3.14
# bool True
# NoneType None

Вложенные структуры разных типов

complex_data = [
    42,                          # int
    "string",                   # str
    [1, 2, 3],                 # list
    {"key": "value"},          # dict
    ("tuple", 1),              # tuple
    {1, 2, 3},                 # set
    lambda x: x * 2            # function
]

print(len(complex_data))  # 7
print(type(complex_data[-1]))  # <class 'function'>
print(complex_data[-1](5))  # 10

Различие между list и array

list (встроенный тип)

# list может хранить всё
my_list = [1, "two", 3.0, None, []]
my_list[0] = "changed"  # Можно менять тип
my_list.append({})      # Добавлять разные типы
print(my_list)  # ["changed", "two", 3.0, None, [], {}]

array (модуль array)

import array

# array требует одного типа данных
int_array = array.array('i', [1, 2, 3, 4, 5])
print(int_array)  # array('i', [1, 2, 3, 4, 5])

# Попытка добавить другой тип
int_array.append("string")  # TypeError: must be integer
int_array.append(3.14)      # TypeError: must be integer

# Коды типов:
# 'i' — int
# 'f' — float
# 'b' — signed char
# 'd' — double

numpy.ndarray (NumPy)

import numpy as np

# NumPy тоже требует одного dtype
arr = np.array([1, 2, 3], dtype=np.int32)
print(arr.dtype)  # int32

# Если смешать типы, numpy автоматически приведёт
mixed = np.array([1, 2.5, 3])  # Все станут float
print(mixed)  # [1.  2.5 3. ]
print(mixed.dtype)  # float64

# Для разных типов используй object dtype
obj_array = np.array([1, "hello", 3.14], dtype=object)
print(obj_array)  # [1 'hello' 3.14]

Практические примеры

Хорошо: когда используется в коде одного типа

# Пример из web-приложения
def process_user_data(user_row):
    # SQL вернул: id, name, email, created_at, is_active
    user_id, name, email, created_at, is_active = user_row
    
    # Каждый элемент имеет известный тип
    print(f"User {user_id}: {name}")  # id — int
    print(f"Email: {email}")           # email — str
    print(f"Created: {created_at}")   # created_at — datetime
    print(f"Active: {is_active}")     # is_active — bool

Плохо: когда типы не ясны

# НЕПРАВИЛЬНО: смешанные типы без документации
def calculate_something(items):
    # Что может быть в items? int? float? tuple? None?
    total = 0
    for item in items:
        if item is not None:  # Защита от None
            total += item  # Может упасть если item — string
    return total

calculate_something([1, 2, None, 4])  # 7
calculate_something([1, 2, "three", 4])  # TypeError!

Правильно: типизация с Type Hints

from typing import List, Union

# Явно указываем, что может быть в списке
def process_data(items: List[Union[int, float]]) -> float:
    total = 0.0
    for item in items:
        if isinstance(item, (int, float)):
            total += item
    return total

process_data([1, 2.5, 3])  # 6.5
process_data([1, 2, None])  # Mypy будет ругаться

Производительность

list (медленнее для больших данных)

import sys
import time

# list хранит ссылки на объекты
my_list = list(range(1_000_000))
print(sys.getsizeof(my_list))  # ~8 MB (много overhead)

# Доступ медленнее
start = time.time()
for _ in range(1_000_000):
    my_list[0]  # Нужно разыменовать ссылку
print(f"List access: {time.time() - start:.3f}s")

array/numpy (быстрее для однородных данных)

import array
import numpy as np
import time

# array использует сырую память
int_array = array.array('i', range(1_000_000))
print(sys.getsizeof(int_array))  # ~4 MB (нет overhead)

# Доступ быстрее
start = time.time()
for _ in range(1_000_000):
    int_array[0]
print(f"Array access: {time.time() - start:.3f}s")

# NumPy самый быстрый
np_array = np.arange(1_000_000, dtype=np.int32)
start = time.time()
for _ in range(1_000_000):
    np_array[0]
print(f"NumPy access: {time.time() - start:.3f}s")

Правильное использование разных типов

Метаданные с разными типами

from dataclasses import dataclass
from typing import Any, Dict
from datetime import datetime

# Вместо смешанного list используй структурированный контейнер
@dataclass
class UserRecord:
    id: int
    name: str
    email: str
    created_at: datetime
    metadata: Dict[str, Any]  # Для гибкости

user = UserRecord(
    id=1,
    name="John",
    email="john@example.com",
    created_at=datetime.now(),
    metadata={"source": "api", "version": 2}
)

print(user.id)  # type-safe
print(user.metadata["source"])  # гибкий

Полиморфизм (разные объекты одного интерфейса)

from abc import ABC, abstractmethod
from typing import List

class Shape(ABC):
    @abstractmethod
    def area(self) -> float:
        pass

class Circle(Shape):
    def __init__(self, radius: float):
        self.radius = radius
    
    def area(self) -> float:
        return 3.14 * self.radius ** 2

class Rectangle(Shape):
    def __init__(self, width: float, height: float):
        self.width = width
        self.height = height
    
    def area(self) -> float:
        return self.width * self.height

# Список разных типов, но одного интерфейса
shapes: List[Shape] = [
    Circle(5),
    Rectangle(3, 4),
    Circle(2)
]

# Работаем единообразно
for shape in shapes:
    print(f"Area: {shape.area()}")

Лучшие практики

  • Используй list для гетерогенных данных — но с осторожностью
  • Типизируй код — Union[type1, type2] или Protocol
  • Структурируй данные — dataclass, namedtuple, TypedDict
  • Для однородных данных используй array/numpy — быстрее и меньше памяти
  • Документируй смешанные типы — добавляй docstring
  • Проверяй типы в runtime — isinstance() для защиты
  • Используй mypy — статическая проверка типов

Повть, что Python списки поддерживают смешанные типы, в production-коде лучше явно документировать или использовать типизацию и структурированные типы данных (dataclass, namedtuple и т.д.).