Предпочтение словарей над объектами в Python - PullRequest
3 голосов
/ 29 августа 2011

Есть ли преимущества в использовании словарей вместо объектов в Python (или наоборот), когда все, что вы делаете, описывает свойства чего-либо?

В проекте, над которым я сейчас работаю, есть несколько мест, где используются словари, в которых я бы обычно создавал объекты. На мой взгляд, объекты обеспечивают большую структуру и позволяют лучше проверять ошибки программиста такими программами, как pylint, но трудно объяснить , почему я бы использовал объект, а не диктовку.

В качестве примера макета один модуль создает виджеты и содержит такой метод, как этот:

def create(self, propertyA, propertyB=55, propertyC="default", 
           propertyD=None, propertyE=None, propertyF=None, propertyG=None,
           propertyH=None, propertyI=None):

Этот метод будет вызван созданием словаря и передачей его примерно так:

widget_client = WidgetClient()
widget = {
    "propertyA": "my_widget",
    "propertyB": 10,
    ...
}
widget_client.create(**widget)

Когда я вижу это, я вижу, что каждое из этих свойств является тем, что описывает «виджет», и хочу сделать следующее:

class Widget(object):
    """Represents a widget."""

    def __init__(self, propertyA, **kwargs):
        """Initialize a Widget.

        :param propertyA: The name of the widget.
        :param kwargs: Additional properties may be specified (see below).
        :returns: None

        """
        self.propertyA = propertyA
        self.propertyB = kwargs.get("propertyB", 55)
        self.propertyC = kwargs.get("propertyC", "default")
        self.propertyD = kwargs.get("propertyD", None)
        self.propertyE = kwargs.get("propertyE", None)
        self.propertyF = kwargs.get("propertyF", None)

А затем обновите метод create (), чтобы он выглядел примерно так:

def create(self, widget):

Что в итоге называется так:

widget_client = WidgetClient()
widget = Widget(propertyA="my_widget")
widget.propertyB = 10
...
widget_client.create(widget)

По-моему, это явно лучше, но я ошибался в прошлом и не могу придумать, как объяснить себя. Конечно, я все еще использую ** kwargs, которых можно избежать, разбив виджет на более мелкие компоненты / связанные части и создавая больше объектов и т. Д. И т. Д., Но я считаю, что это хороший «первый шаг». Имеет ли это какой-либо смысл вообще?

Преимущества словаря :

  1. Быстрее и / или более эффективный объем памяти

Недостатки словаря :

  1. Невозможность отловить некоторые ошибки при проверке статического кода
  2. Полный список всех свойств виджета может никогда не появиться или быть известным

Преимущества объектов :

  1. Точное знание, из чего состоит «Виджет»
  2. Потенциально ловить ошибки с помощью статических программ проверки кода (хотя использование ** magic предотвращает некоторые из них)

Недостатки объектов :

  1. Медленная и / или менее эффективная память

Это кажется глупым вопросом, но зачем делать что-то с объектами, которые можно сделать с помощью словарей?

Ответы [ 4 ]

2 голосов
/ 29 августа 2011

Использование любого встроенного типа данных всегда дает вам преимущество некоторых функций, плюс его поведение хорошо известно другим программистам. Словарь дает вам полный набор встроенных методов, и никто не задается вопросом, является ли он итеративным.

Это только одно преимущество. Не то чтобы я говорил, что вы всегда должны использовать словари, а не декларировать свои собственные объекты. (и, конечно, ваш новый объект может наследовать поведение, подобное словарю). Но вы не всегда должны выбирать создание нового объекта, когда это может сделать более простой механизм хранения. Использование понимания в качестве руководства будет зависеть от того, было ли у Виджета какое-либо особое поведение или атрибуты.

2 голосов
/ 29 августа 2011

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

Может быть преимущество использования объектов вместо словарей.Смотри: http://docs.python.org/reference/datamodel.html#slots

1 голос
/ 29 августа 2011

Вы можете реализовать это с помощью namedtuple .Например, вы можете создать именованный набор виджетов со значениями по умолчанию:

>>> from collections import namedtuple
>>> _Widget = namedtuple("Widget", "propertyA propertyB propertyC propertyD propertyE propertyF propertyG propertyH propertyI")
>>> DefaultWidget = _Widget(None, 55, "Default", None, None, None, None, None, None)
>>> DefaultWidget
Widget(propertyA=None, propertyB=55, propertyC='Default', propertyD=None, propertyE=None, propertyF=None, propertyG=None, propertyH=None, propertyI=None)

Затем вы можете иметь функцию Widget, которая инициализирует свойства:

def Widget(propertyA, **kwargs):
   return DefaultWidget._replace(propertyA=propertyA, **kwargs)

Затем вы можете использовать егокак это:

>>> Widget("test", propertyE=17)
Widget(propertyA='test', propertyB=55, propertyC='Default', propertyD=None, propertyE=17, propertyF=None, propertyG=None, propertyH=None, propertyI=None)

Обратите внимание, что если вы пытаетесь опустить обязательное свойство A:

>>> Widget()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Widget() takes exactly 1 argument (0 given)

или если вы даете свойство, которое не существует:

>>> Widget("test", propertyZ="test2")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in Widget
  File "<string>", line 32, in _replace
ValueError: Got unexpected field names: ['propertyZ']

это хорошо с этим справляется.Я думаю, что использование namedtuple избавит вас от недостатков использования словаря.

0 голосов
/ 18 марта 2012

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

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