Каковы лучшие практики Python для констант ключа словаря?

При использовании словарных (dict) ключей в Python, похоже, существует несколько общих подходов:

  • some_dict['key_name'] # string constants everywhere

  • some_dict[KeyConstants.key_name] # where class KeyConstants: key_name: 'key_name'

  • some_dict[KEY_NAME] # with from some_module import KEY_NAME # a module level constant

    • "key_name" имеет тот недостаток, что вы повторяете константы во всем коде. Это не СУХОЙ. Хуже того, если вы когда-нибудь захотите опубликовать свой API (в самом широком смысле), у вас будут потребители вашего API, которые повторяют эти константы повсюду, и если вы когда-либо захотите изменить "key_name" на "better_key_name", это будет изменением.

    • Это типизированный язык, СУХОЙ подход, с константами, объединенными в одном месте. Его единственные недостатки в том, что он уродливый, немного менее читаемый и более многословный. Принципы пифонов в первую очередь запрещают это. Это позволяет вам легко изменять константу, представляющую ключ, поскольку все кодируются против переменной KeyConstants.key_name. Он также хорошо работает с IDE для рефакторинга.

    • Константы уровня модуля рекомендуются в руководстве по стилю PEP 8. ALL_CAPS_ARE_LOUD и сложнее ввести. Это имеет некоторые преимущества обоих вариантов 1 и 2.

Каковы некоторые другие рекомендации для констант ключа ключа? Какой из вышеуказанных подходов является предпочтительным и когда?

Ответы

Ответ 1

  • д [ 'key_name']
  • д [Keys.key_name]
  • д [KEY_NAME]

Я действительно не рассматриваю # 3 как требующий импорт на уровне модуля; они просто могут быть в имени модуля, например, вы могли бы сделать что-то вроде Как программно установить глобальную (модульную) переменную?

Преимущество # 2 над # 1 заключается в том, что опечатки и устаревшие значения выдают ошибку атрибута "этот ключ не существует!" а не ошибка индекса "не удалось найти!" - который всегда лучше. # 2 > # 1. Это не более подробный, потому что вы просто устанавливаете K=Keys (или что-то еще), если вы печатаете много, поэтому у вас есть d[K.key_name], всего два символа больше(). Например, в зависимости от того, как я себя чувствую, я могу сделать это:

import subprocess as proc
proc.Popen(..., stdout=proc.PIPE)

или

import subprocess as proc
PIPE = proc.PIPE
proc.Popen(..., stdout=PIPE)

или

from subprocess import *
Popen(..., stdout=PIPE)

Что касается № 3, ALL_CAPS_ARE_LOUD по какой-либо причине; становится нечетко различать d[someVariable] (который может содержать любое ключевое слово) и d[magicKeyword] - тогда как d[MAGIC_KEYWORD] недвусмысленно указывает, что это константа, а не какая-либо переменная, которая может содержать константу, например. for someVariable in magicKeywords. # 3 в основном эквивалентен до # 2, например. re.DOTALL (reэквивалентен KeyConstants, не запомнив имя контейнеров KeyConstants, потому что он ). Таким образом, № 3 превосходит # 2, если вы не находитесь в странной ситуации, когда у вас разные типы кластеров.

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

Вы также можете рассмотреть # 4, который должен придать вашему словарю атрибуты, например. d.key_name - это подходит только в том случае, если это некоторый объект подкачки.

Но процитировать комментарий Йохена Ритцеля: "Использование постоянных ключей должно быть очень редким случаем" (использовать атрибуты объекта или, как он предлагает, возможно, именованный кортеж, хотя я всегда находили их громоздкими)

Ответ 2

Это старый вопрос, но вы проверили Bunch? Это словарь, который поддерживает доступ в стиле атрибута, a la JavaScript.

>>> from bunch import bunchify
>>> from bunch import unbunchify
>>> import datetime as dt

>>> my_dict = {'a': 'a', 'b': [{'c': 'c', 'n': 1}, {'c': 'k', 'n': 2}], 'dt': dt.datetime.utcnow()}

>>> my_dict_obj = bunchify(my_dict) 
>>> my_dict_obj.b[0].c
'c'
>>>  'a' in my_dict_obj
True
>>>  'x' in my_dict_obj
False
>>> my_dict = unbunchify(my_dict_obj)