DevGang
Авторизоваться

Сравните Dictionary, NamedTuple, класс Data и модель Pydantic в Python

Python - это объектно-ориентированный язык программирования, и существуют различные способы представления данных в виде объектов. Простые объекты могут быть представлены словарями с парами ключ-значение. А более сложные могут быть представлены некоторыми специальными классами данных, включая namedtuple, data class и Pedantic models.

В этом посте мы познакомим вас с этими типами данных на простых примерах. Затем мы можем выбрать тот, который наиболее подходит для решения конкретных задач.

Словари

Первый тип данных, который нужно представить, — это dict, который представляет собой встроенный контейнерный тип данных общего назначения в Python. Словари называются объектами или хэш-картами в других языках программирования и используются для хранения пар ключ-значение. Например, в этом dict хранится запись об ученике с данными об имени, возрасте и баллах:

student = {"name": "John", "age": 15, "scores": ["A", "B", "B", "C", "C", "C"]}

dict — это просто базовый тип данных, который мы собираемся представить, и который большинство из нас уже должно знать. Однако позже будут представлены более интересные и полезные, которые могут быть новыми для многих читателей.

Существует специальный подкласс dict, называемый defaultdict, который обычно используется для применения фабричной функции для предоставления отсутствующих значений. Фабричная функция, такая как list или int, обычно используется для предоставления начального значения, когда значение ключа еще не присвоено. Например, list сгенерирует пустой список, а int вернет 0.

Давайте рассмотрим простой пример для подсчета вхождений каждой оценки:

from collections import defaultdict

scores = ["A", "B", "B", "C", "C", "C"]

score_counts = defaultdict(int)

for score in scores:
    # The initial count for each score will be set to be 0.
    score_counts[score] += 1

print(score_counts)
# defaultdict(int, {'A': 1, 'B': 2, 'C': 3})

defaultdict полезен, когда мы хотим установить начальное значение для ключа в dict только тогда, когда это необходимо, и не хотим заранее явно инициализировать все ключи dict некоторыми начальными значениями.

NamedTuple

namedtuple — это подкласс кортежа, который можно использовать для создания объектов, похожих на кортежи, которые ведут себя как кортежи и как объекты. В частности, вы можете получить доступ к значениям как по атрибутам, так и по индексам. Однако у него также есть ограничение кортежей, заключающееся в том, что значения не могут быть изменены.

Все это можно продемонстрировать на нашем простом примере:

from collections import namedtuple

Student = namedtuple("Student", field_names=["name", "age", "scores"])

# Create an instance of the one-line namedtuple class.
student = Student(name="John", age=15, scores=["A", "B", "B", "C", "C", "C"])

# The type is a class.
type(student)
# __main__.Student

# We can access values by indexes like a tuple.
student[0]  # John
# We can also access values by attributes like an object.
student.name  # John
# However, we cannot access by keys like a dict.
student["name"]
# TypeError: tuple indices must be integers or slices, not str

# And we cannot change the value because it's a tuple.
student.age = 16
# AttributeError: can't set attribute

Мы можем преобразовать namedtuple в dict с помощью метода _asdict().

student._asdict()
# {'name': 'John', 'age': 15, 'scores': ['A', 'B', 'B', 'C', 'C', 'C']}

Обратите внимание, что префикс подчеркивания используется для предотвращения конфликтов с именами полей. Это не означает, что метод является приватным методом класса namedtuple, который не следует использовать.

Собственный data class

В Python есть специальный декоратор dataclasses.dataclass, который может пометить обычный класс как так называемый класс данных. Классы данных — это обычные классы Python с некоторыми специальными методами, такими как __init__() и __repr__(), автоматически добавляемыми декоратором класса данных. В них удобно хранить и сравнивать данные.

Давайте используем класс данных для наших данных о студентах выше:

from dataclasses import dataclass

@dataclass
class Student:
    name: str
    age: int
    scores: list[str]

# Normal usage:
student = Student(name="John", age=15, scores=["A", "B", "B", "C", "C", "C"])

print(student)
# Generated by the __repr__ magical method added by the dataclass decorator.
# Student(name="John", age=15, scores=["A", "B", "B", "C", "C", "C"])

Однако классы данных просто хранят данные как есть и не выполняют никакого преобразования или проверки данных:

# The data types are not converted.
student = Student(name="John", age="15", scores=[60, 70])
print(student)
# Student(name='John', age='15', scores=[60, 70])

# And no error will be raised when the data types are not coercible.
student = Student(name="John", age="young", scores="A")
print(student)
# Student(name='John', age='young', scores='A')

Ограничения собственных классов данных могут быть решены с помощью классов данных Pydantic.

Pydantic класс данных

pydantic.dataclasses.dataclass — это замена dataclasses.dataclass с преобразованием и проверкой данных. Давайте посмотрим, как это работает на нашем простом примере:

from pydantic.dataclasses import dataclass

@dataclass
class Student:
    name: str
    age: int
    scores: list[str]

# Normal usage:
student = Student(name="John", age=15, scores=["A", "B", "B", "C", "C", "C"])

# Coercible data types are converted automatically.
student = Student(name="John", age="15", scores=[60, 70])
print(student)
# Student(name="John", age=15, scores=["60", "70"])

# An error will be raised if the data is not coercible.
student = Student(name="John", age="young", scores="A")
# ValidationError: 2 validation errors for Student
# age
#   value is not a valid integer (type=type_error.integer)
# scores
#   value is not a valid list (type=type_error.list)

Как показано выше, Pydantic dataclass создается так же, как и собственный dataclass, с дополнительными преимуществами преобразования и проверки данных.

Pydantic модель

Наш любимый тип данных — BaseModel от Pydantic, который обладает всеми преимуществами dataclass, а также тем преимуществом, что его легче наследовать и настраивать.

from pydantic import BaseModel

class Student(BaseModel):
    name: str
    age: int
    scores: list[str]

# Normal usage:
student = Student(name="John", age=15, scores=["A", "B", "B", "C", "C", "C"])

# coercible data types are converted automatically.
student = Student(name="John", age="15", scores=[60, 70])
print(student)
# name='John' age=15 scores=['60', '70']

# An error will be raised if the data is not coercible.
student = Student(name="John", age="young", scores="A")
# ValidationError: 2 validation errors for Student
# age
#   value is not a valid integer (type=type_error.integer)
# scores
#   value is not a valid list (type=type_error.list)

Многие из нас могут спросить, поскольку BaseModel лучше, чем dataclass, почему нам все еще нужно использовать dataclass. Если у вас такая же путаница, то эта проблема GitHub прояснит ее для вас. По сути, основная причина использования dataclasses состоит в том, чтобы упростить работу с унаследованным кодом, не изменяя слишком много кода.

Мы только что коснулись моделей Pydantic, и нам предстоит еще многое изучить. Pydantic — действительно мощный инструмент, который можно использовать для очень гибкой проверки ваших данных с помощью настраиваемых валидаторов. Во многих случаях он может даже заменить схему JSON для проверки данных.

Помимо проверки данных, Pydantic можно использовать для чтения переменных среды, что является действительно классной и удобной функцией.

Вывод

В этом посте мы рассмотрели некоторые распространенные структуры данных, включая модели dict, namedtuple, dataclass и Pydantic. Для очень простых пар ключ-значение лучше всего подходит dict, потому что для него не нужно создавать класс. Если нам нужно получить доступ к некоторым данным как по индексу, так и по атрибутам, тогда namedtuple — лучший выбор. А если нам нужно преобразование и проверка данных, то лучше всего подойдет Pydanic BaseModel. dataclass используется не так часто, и большинство его функций могут быть реализованы в моделях Pydantic.

#Python #Data Science
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу