Python字典dict键常量的最佳实践是什么?

26
当在Python中使用字典(dict)键时,似乎有几种通用方法:
  1. some_dict['key_name'] # 在代码中到处重复字符串常量

  2. some_dict[KeyConstants.key_name] # 使用类KeyConstants:key_name定义常量

  3. some_dict[KEY_NAME] # 使用from some_module import KEY_NAME导入模块级常量

    1. 'key_name'的缺点是在代码中反复出现常量,不符合DRY原则。更糟糕的是,如果你发布API(在广义上),API的使用者都需要在代码中反复使用这些常量。如果你想将'key_name'改为'better_key_name',这将是一个破坏性的变化。

    2. 这是一种类型语言、符合DRY原则的方法,将所有常量整合到一个地方。唯一的缺点是它很丑陋,可读性稍差,而且有些啰嗦。这与Pythonic原则相违背。它让你很容易地改变代表键的常量,因为每个人都编写针对变量KeyConstants.key_name的代码。它也很适合IDE进行重构。

    3. 模块级别的常量是PEP 8样式指南推荐的。使用ALL_CAPS_ARE_LOUD表示,且更难输入。这种方法具有选项1和2的某些优点。

在使用字典键常量时,还有哪些最佳实践?以上哪种方法是首选,什么时候使用?

3
为什么一开始就要有这么多不变的键?为什么不使用模块级别的变量或类似记录的对象来保存属性? - user395760
6
如果键是可变的,那么使用字典是不错的选择;否则,你可以使用命名元组或类上的属性。使用固定键应该是非常罕见的情况。 - Jochen Ritzel
3
使用JSON或处理没有ORM的数据库/NoSQL存储(例如未使用MongoEngine的pymongo)时,具有键的字典问题非常普遍。虽然您可以将字典键包装到具有属性的类中,但如果底层数据最初为字典,则最终将得到一堆丑陋的打包/拆包管道代码。 - velshin
2个回答

9
  1. d['key_name']:使用字符串作为键名。
  2. d[Keys.key_name]:使用变量作为键名,可以避免拼写错误和过时值的问题,如果键名不存在会抛出属性错误而不是索引错误。
  3. d[KEY_NAME]:与第一种方式类似,但是使用大写字母。

个人认为第三种方式不需要进行模块级别的导入,只需要将其置于模块命名空间中即可。例如,您可以参考如何以编程方式设置全局(模块)变量?

相对于第一种方式,第二种方式的优点在于可以避免拼写错误和过时值的问题,如果键名不存在会抛出属性错误而不是索引错误,这总是更好的选择。因此,我认为第二种方式优于第一种。而且,它并不比第一种方式更冗长,因为你只需要设置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)

关于第三点,全大写是有原因的;如果不这样做,则很难区分d[someVariable](可以包含任何关键字)和d[magicKeyword]——而d[MAGIC_KEYWORD]则明确表示它是一个常量,而不是可能包含常量的变量,例如for someVariable in magicKeywords。第三点基本上等同于第二点,例如re.DOTALLre相当于KeyConstants,无需记住KeyConstants容器的名称,因为它就是该模块)。因此,除非您处于具有不同类型的键空间的奇怪情况,否则第三点优于第二点。

DRY / OAOO非常重要,但最终与这些内容无关,因为您总是需要重复变量名才能引用它;您所能做的最好的事情就是创建别名。

您还可以考虑第四点,即赋予字典属性,例如d.key_name——这只适用于某些可订阅对象。

但是引用Jochen Ritzel的评论:“使用常量键应该是非常罕见的”(使用对象的属性,或者如他建议的命名元组,尽管我始终觉得它们难以使用)。


1
感谢您的周到回复。请注意,使用任何NAMED_CONSTANTS,我们都可以DRY常量的值;即使它们是键也是如此。当您的键被映射到JSON或数据库时,字典键名和NAMED_CONSTANT_KEY可能会独立变化,这一点变得更加清晰。 - velshin

1

这是一个老问题,但你是否尝试过Bunch?它是一个支持属性式访问的字典,类似于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)

Bunch 似乎已经死了。 - coler-j

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接