Использование класса Python в качестве контейнера данных - PullRequest
45 голосов
/ 29 июля 2010

Иногда имеет смысл группировать связанные данные вместе.Я склонен делать это с помощью слова, например,

self.group = dict(a=1, b=2, c=3)
print self.group['a']

Один из моих коллег предпочитает создавать класс

class groupClass(object):
    def __init__(a, b, c):
        self.a = a
        self.b = b
        self.c = c
self.group = groupClass(1, 2, 3)
print self.group.a

Обратите внимание, что мы не определяем какие-либо методы класса.

Мне нравится использовать dict, потому что я люблю минимизировать количество строк кода.Мой коллега считает, что код будет более читабельным, если вы используете класс, и в будущем вам будет проще добавлять в него методы.

Что вы предпочитаете и почему?

Ответы [ 11 ]

43 голосов
/ 29 июля 2010

Если вы действительно никогда не определяете какие-либо методы класса, на мой взгляд, dict или namedtuple имеют гораздо больше смысла.Простой + встроенный - это хорошо!Впрочем, каждому свое.

24 голосов
/ 13 декабря 2017

Справочная информация

Резюме альтернативных контейнеров данных, основанных на атрибутах, было представлено Р. Хеттингером на встрече праздника SF Python 2017 года.Смотрите его твит и его слайд-колоду .Он также дал доклад на PyCon 2018 по классам данных.

Другие типы контейнеров данных упоминаются в этой статье и преимущественно в документации по Python 3 (см. Ссылки ниже).

Здесь обсуждается список рассылки python-ideas о добавлении recordclass в стандартную библиотеку.

Опции

Альтернативы в стандартной библиотеке

  • collections.namedtuple: кортеж с атрибутами (см. Семенной рецепт )
  • typing.NamedTuple: подклассифицируемый кортеж (см. Этот пост , сравнивая его с namedtuple)
  • types.SimpleNamespace: простокласс с необязательным объявлением класса
  • types.MappingProxy: dict только для чтения
  • enum.Enum: ограниченный набор связанных констант (ведет себякак класс)
  • dataclasses.dataclass: изменяемый именованный кортеж с классами по умолчанию / без шаблонов

Внешние опции

  • records : изменяемый именованный кортеж (см. Также recordclass )
  • Связки : добавить атрибут доступа к диктовкам (вдохновение для SimpleNamedspace)
  • box : обтекание диктов с поиском в точечном стиле функциональность
  • attrdict : доступ к элементам из сопоставления в виде ключей или атрибутов
  • поля : удалить шаблон из классов контейнеров.
  • namedlist : изменяемые контейнеры, похожие на кортежи, по умолчанию E. Smith

Какой?

Решение о том, какой вариант использовать, зависит от ситуации (см. Примеры ниже).Обычно достаточно старомодный изменяемый словарь или неизменный именованный набор.Классы данных являются новейшим дополнением (Python 3.7a), предлагающим как изменчивость, так и необязательную неизменяемость , с обещанием уменьшения стандартного шаблона, вдохновленного проектом attrs .


Примеры

import typing as typ
import collections as ct
import dataclasses as dc


# Problem: You want a simple container to hold personal data.
# Solution: Try a NamedTuple.
>>> class Person(typ.NamedTuple):
...     name: str
...     age: int
>>> a = Person("bob", 30)
>>> a
Person(name='bob', age=30)

# Problem: You need to change age each year, but namedtuples are immutable. 
# Solution: Use assignable attributes of a traditional class.
>>> class Person:
...     def __init__(self, name, age):
...         self.name = name
...         self.age = age
>>> b = Person("bob", 30)
>>> b.age = 31
>>> b
<__main__.Person at 0x4e27128>

# Problem: You lost the pretty repr and want to add comparison features.
# Solution: Use included repr and eq features from the new dataclasses.
>>> @dc.dataclass(eq=True)
... class Person:
...     name: str
...     age: int
>>> c = Person("bob", 30)
>>> c.age = 31
>>> c
Person(name='bob', age=31)
>>> d = Person("dan", 31)
>>> c != d
True
8 голосов
/ 29 июля 2010

Я предпочитаю следовать ЯГНИ и использовать дикт.

7 голосов
/ 02 октября 2017

Существует новое предложение, направленное на реализацию именно того, что вы ищете, под названием классы данных . Посмотрите на это.

Использование класса над диктовкой - вопрос предпочтений. Лично я предпочитаю использовать dict, когда ключи не известны априори. (Как картографический контейнер).

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

Лично для меня, пожалуй, самая главная причина использования класса - использовать функцию автозаполнения IDE! (технически слабая причина, но очень полезная на практике)

5 голосов
/ 20 июля 2018

Кстати, я думаю, что Python 3.7 реализовал @ dataclass - самый простой и эффективный способ реализации классов как контейнеров данных.

@dataclass
class Data:
    a: list
    b: str    #default variables go after non default variables
    c: bool = False

def func():
    return A(a="hello")

print(func())

Вывод будет: hello

Он слишком похож на класс case, как Scala, и самый простой способ использовать класс в качестве контейнера.

5 голосов
/ 29 июля 2010

Твой путь лучше. Не пытайтесь предвидеть будущее слишком сильно, поскольку вы вряд ли добьетесь успеха.

Однако, иногда имеет смысл использовать что-то вроде структуры C , например, если вы хотите идентифицировать разные типы, а не использовать dicts для всего.

3 голосов
/ 16 декабря 2016

Вы можете комбинировать преимущества dict и class вместе, используя некоторый класс-оболочку, унаследованный от dict.Вам не нужно писать шаблонный код, и в то же время можете использовать точечную запись.

class ObjDict(dict):
    def __getattr__(self,attr):
        return self[attr]
    def __setattr__(self,attr,value):
        self[attr]=value

self.group = ObjDict(a=1, b=2, c=3)
print self.group.a
2 голосов
/ 29 июля 2010

Я не согласен с тем, что код более читабелен при использовании класса без методов. Обычно вы ожидаете функциональность от класса, а не только от данных.

Итак, я бы пошел на диктовку, пока не возникнет необходимость в функциональности, и тогда конструктор класса мог бы получить диктат: -)

1 голос
/ 02 марта 2018

Как насчет Prodict :

group = Prodict(a=1, b=2, c=3)
group.d = 4

А если вы хотите автоматическое преобразование типов и автоматическое завершение кода (intelli-sense):

class Person(Prodict):
    name: str
    email: str
    rate: int

john = Person(name='John', email='john@appleseed.com')
john.rate = 7
john.age = 35  # dynamic
1 голос
/ 29 июля 2010

Диктант явно подходит для этой ситуации.Он был разработан специально для этого варианта использования.Если вы на самом деле не собираетесь использовать класс в качестве класса, нет смысла заново изобретать колесо и нести дополнительные издержки / тратить пространство класса, которое действует как плохой словарь (без словарных функций).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...