简体   繁体   中英

What are Python best practices for dictionary dict key constants?

When using dictionary (dict) keys in Python, there seem to be a few general approaches:

  1. some_dict['key_name'] # string constants everywhere

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

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

    1. 'key_name' has the disadvantage that you're repeating constants throughout your code. It's not DRY. Worse, if you ever go to publish an your API (in the broadest sense) you'll have consumers of your API repeating these constants everywhere, and if you ever want to change 'key_name' to 'better_key_name' it will be a breaking change.

    2. This is the typed language, DRY approach, with constants consolidated in one place. Its only disadvantages are that it's ugly, a bit less readable, and more verbose. Pythonic principles primarily prohibit that. It lets you easily change the constant representing the key, since everyone's coding against the variable KeyConstants.key_name. It also works well with IDEs for refactoring.

    3. Module level constants are recommended in the PEP 8 style guide. ALL_CAPS_ARE_LOUD and harder to type. This has some of the advantages of both options 1 and 2.

What are some other best practices for dict key constants? Which of the above approaches are preferred and when?

  1. d['key_name']
  2. d[Keys.key_name]
  3. d[KEY_NAME]

I don't really view #3 as requiring module-level imports; they just can be in the module namepsace, eg you could do something like How to programmatically set a global (module) variable?

The advantage of #2 over #1 is that typos and obsolete values will throw an attribute error "this key doesn't exist!" rather than an index error "could not be found!" -- which is always better. #2>#1. It's not more verbose either, because you just set K=Keys (or something) if you're typing a lot, so you have d[K.key_name] , just two characters more (). For example, depending how before I'm feeling, I may do either:

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

or

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

or

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

With regards to #3, ALL_CAPS_ARE_LOUD for a reason; it becomes confusing to distinguish between d[someVariable] (which can be holding any keyword) and d[magicKeyword] -- whereas d[MAGIC_KEYWORD] is unambiguous that it is a constant, and not some variable which may be holding a constant, eg for someVariable in magicKeywords . #3 basically is equivalent to #2, eg re.DOTALL (the re being equivalent to KeyConstants , without having to remember the name of the KeyConstants containers because it is the module). Thus #3 is superior to #2 unless you are in a strange situation where you have different types of keyspaces.

DRY / OAOO is very very important, but ultimately is not relevant to any of these, because you always need to repeat a variable name in order to refer to it; the best you can do is create an alias.

You could also consider #4, which is to endow your dictionary with attributes, eg d.key_name -- this is only appropriate if it's some subscriptable object.

But to quote a comment by Jochen Ritzel: "Using constant keys should be a very rare occasion" (use attributes of an object, or as he suggests perhaps a named tuple, though I've always found them to be unwieldy)

It is an old question, but have you checked out Bunch ? It is a dictionary that supports attribute-style access, 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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM