Когда использовать класс вместо dict

#python

#python

Вопрос:

Пользовательские данные следующим образом:

 user = {"id": 1, "firstName": "Bar", "surname": "Foosson", "age": 20}
  

отправляется в приложение через json.

Во многих местах кода это сделано следующим образом:

 user["firstName"]   " "   user["surname"]
  

что наводит меня на мысль, что следует использовать функцию:

 def name(user):
    return user["firstName"]   " "   user["surname"]
  

что, в свою очередь, наводит меня на мысль, что код должен быть переработан с использованием User класса вместо name метода. Согласны ли вы и есть ли какие-либо аргументы в пользу того, чтобы не проводить рефакторинг кода для использования класса вместо этого?

Комментарии:

1. В сторону, используйте "{firstName} {surname}".format(**user) . 😉

2. Еще один аспект: в Python эти вещи называются «dicts» (их тип dict ); называть их «maps» может сбивать с толку (из-за map ).

3. Я бы использовал класс, даже если в этом не было необходимости def name(user) . Как правило, если ключи dict фиксированы (вы всегда ожидаете иметь имя, фамилию), это указывает на то, что вам, вероятно, не следует использовать dict .

4. @Bhargav Rao Что, если кто-то случайно написал «{FirstName} {фамилия}».format(** user), где случайно есть два пробела между «}» и «{«? Конечно user.name () лучше.

5. @Baz что, если кто-то случайно написал два пробела " " ? Конечно, Бхаргав прав. Будь как Бхаргав.

Ответ №1:

Я уверен, что вы не решаетесь использовать классы из-за необходимости писать шаблонный код.

Но есть хорошая библиотека, которая может облегчить вашу жизнь : attrs .

В Glyph есть сообщение с говорящим названием: единственная библиотека Python, которая нужна всем. Конечно, это самоуверенная статья, но вот цитата со страницы примеров:

 >>> @attr.s
... class Coordinates(object):
...     x = attr.ib()
...     y = attr.ib()
  

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

 >>> c1 = Coordinates(1, 2)
>>> c1
Coordinates(x=1, y=2)
>>> c2 = Coordinates(x=2, y=1)
>>> c2
Coordinates(x=2, y=1)
>>> c1 == c2
False
  

Это довольно удобная библиотека, так что проверьте ее.

Вот пример вашего User класса:

 import attr

@attr.s
class User(object):

    id = attr.ib()
    firstName = attr.ib()
    surname = attr.ib()
    age = attr.ib()

    @property
    def name(self):
        return '{0.firstName} {0.surname}'.format(self)

user_dict = {'id': 1, 'firstName': 'Bar', 'surname': 'Foosson', 'age': 20}
user = User(**user_dict)
assert user.name == 'Bar Foosson'
  

Ответ №2:

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

В вашей ситуации, если атрибуты пользователя доступны только для чтения, мой подход действительно будет использовать namedtuple . Вы получаете неизменность атрибутов, эффективность использования памяти, и вы все равно можете установить name предварительно определенный метод, который будет использоваться точно так же, как вы бы использовали property в классе:

 from collections import namedtuple

@property
def name(self):
    return '{} {}'.format(self.firstName, self.surname)

User = namedtuple('User', 'id firstName surname age')
User.name = name

user = User(1, 'Bar', 'Foosson', 20)
print(user.name)  # Bar Foosson

user = User(2, 'Another', 'Name', 1)
print(user.name)  # Another Name