Каковы лучшие практики Python в отношении dicts против объектов для простого хранения значения ключа? - PullRequest
4 голосов
/ 04 февраля 2012

После некоторого времени программирования на Javascript я немного полюбил двойственность между объектами и ассоциативными массивами (словарями):

//Javascript
var stuff = { a: 17, b: 42 };

stuff.a;    //direct access    (good sugar for basic use)
stuff['a']; //key based access (good for flexibility and for foreach loops)

В Python есть два основных способа сделать подобные вещи.(насколько я знаю)

Словари:

stuff = { 'a': 17, 'b':42 };

# no direct access :(
stuff['a'] #key based access

или объекты:

#use a dummy class since instantiating object does not let me set things
class O(object):
    pass

stuff = O()
stuff.a = 17
stuff.a = 42

stuff.a #direct access :)
getattr(stuff, 'a') #key based access

edit: В некоторых ответах также упоминается namedtuples как простой способ создания легких классов для неизменяемых объектов.


Итак, мои вопросы:

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

  2. Я могу представить, что есть много способов создать маленькие вспомогательные классы, чтобы сделать объектный подход менее уродливым (например, что-то, что получает указание на конструктор и затем переопределяет __getattribute__).Это хорошая идея или я слишком обдумываю это?

    • Если это хорошая вещь, какой будет самый хороший подход?Кроме того, будут ли какие-нибудь хорошие проекты Python, использующие упомянутый подход, из которого я мог бы черпать вдохновение?

Ответы [ 4 ]

8 голосов
/ 04 февраля 2012

Не уверен насчет "признанных лучших практик", но я делаю следующее:

  1. Если типы значений однородны, т. Е. Все значения в отображениях являются числами, используйте dict.
  2. Если значения неоднородны и если отображение всегда имеет заданный более или менее постоянный набор ключей, используйте объект.(Предпочтительно использовать фактический класс, так как он пахнет очень похоже на тип данных.)
  3. Если значения неоднородны, но ключи в отображении меняются, подбросьте монету.Я не уверен, как часто этот шаблон используется в Python, словари, подобные этому, особенно часто встречаются в Javascript для «поддельных» функций с аргументами ключевых слов.В Python они уже есть, и **kwargs - это диктат, поэтому я бы пошел с диктовками.

Или, другими словами, представляем экземпляры типов данных с объектами.Представлять временные или временные сопоставления с диктовками.Глотайте необходимость использовать синтаксис ['key'] - заставляя Python чувствовать, что Javascript просто кажется мне вынужденным.

4 голосов
/ 04 февраля 2012

Это будет способ выбора между dict и object для хранения простых пар ключ-значение без метода :

  1. Нужно ли перебирать мои пары ключ-значение?
    • Да: используйте dict
    • Нет: перейти к 2.
  2. Сколько ключей у меня будет?
    • Много: используйте dict
    • Немного: перейти к 3.
  3. Важны ли ключевые имена?
    • Нет: используйте dict
    • Да: перейти к 4.
  4. Хочу ли я раз навсегда высечь в камне эти важные ключевые имена?
    • Нет: используйте dict
    • Да: используйте object

Также может быть интересно взглянуть на разницу, показанную dis:

>>> def dictf(d):
...     d['apple'] = 'red'
...     return d['apple']
... 
>>> def objf(ob):
...     ob.apple = 'red'
...     return ob.apple
... 
>>> dis.dis(dictf)
  2           0 LOAD_CONST               1 ('red') 
              3 LOAD_FAST                0 (d) 
              6 LOAD_CONST               2 ('apple') 
              9 STORE_SUBSCR         

  3          10 LOAD_FAST                0 (d) 
             13 LOAD_CONST               2 ('apple') 
             16 BINARY_SUBSCR        
             17 RETURN_VALUE         
>>> dis.dis(objf)
  2           0 LOAD_CONST               1 ('red') 
              3 LOAD_FAST                0 (ob) 
              6 STORE_ATTR               0 (apple) 

  3           9 LOAD_FAST                0 (ob) 
             12 LOAD_ATTR                0 (apple) 
             15 RETURN_VALUE
4 голосов
/ 04 февраля 2012

Что ж, если ключи известны заранее (или даже нет), вы можете использовать именованные кортежи, которые в основном являются легко создаваемыми объектами с любыми выбранными вами полями. Основное ограничение заключается в том, что вы должны знать все ключи во время создания класса кортежей, и они неизменны (но вы можете получить обновленную копию).

http://docs.python.org/library/collections.html#collections.namedtuple

Кроме того, вы почти наверняка можете создать класс, который позволяет динамически создавать свойства.

3 голосов
/ 04 февраля 2012

Ну, два подхода тесно связаны!Когда вы делаете

stuff.a

, вы действительно получаете доступ к

stulff.__dict__['a']

Аналогично, вы можете создать подкласс dict, чтобы заставить __getattr__ возвращать то же самое, что и __getitem__ и так stuff.a также будет работать для вашего dict подкласса.

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

Конечно, вы должны также использовать объекты, когда вам нужно больше, чем простое отображение.Это «больше» обычно будет дополнительным состоянием или дополнительными вычислениями для возвращаемых значений.

Вам также следует подумать о том, как другие будут использовать ваши объекты stuff.Если они знают, что это просто dict, то они также знают, что могут вызвать stuff.update(other_stuff) и т. Д. Это не так ясно, если вы вернете им объект.В основном: если вы думаете, что им нужно манипулировать ключами и значениями вашего stuff как обычного dict, то вам, вероятно, следует сделать его dict.

Что касается наиболее «питонического» способачтобы сделать это, я могу только сказать, что я видел, что библиотеки используют оба подхода:

  • Библиотека BeautifulSoup анализирует HTML и возвращает вам некоторые очень динамичные объекты , где доступ к атрибутам и элементам имеет особое значение.

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

  • Конечно, есть также много библиотек, которые просто возвращают обычные dict объекты - они - хлеби масло многих программ на Python.

...