使用命名元组作为事实上的常量 - 聪明还是愚蠢?

8
我来自C#背景,但现在我做了相当多的Python 3.x科学计算工作,所以我想听听对于Python标准来说,我的风格或语音有多"奇怪"

特别是,Python中没有“const”这样的东西让人非常恼火。 我的使用情况是这样的:我正在保存*.npz文件(数据的numpy序列化字典),传递字典,写文件等等,字典键,文件名等等需要具有一致、可靠的命名方案。
很明显,在8个地方输入相同的魔术愚蠢字符串是错误的。
因此,在我的模块根目录下,我通常会有一个名为base.py的文件:
import os
from collections import namedtuple
from os import path

# This is the tuple that contains operational constants
RuntimeConstants = namedtuple("Const", " ModelDirectoryLabelName \
                                  DefaultModelOutputDirectoryRoot \
                                  ResultDirectoryNameFormat \
                                  PeripheryOutputFilePrefix \
                                  NCOutputFilePrefix \
                                  SummaryPlotFileName \
                                  PeripheryConfigurationName \
                                  ResourceDirectoryName \
                                  StimulusTemplateName")

runtime_consts = RuntimeConstants(ModelDirectoryLabelName=".model-output-root",
                                  DefaultModelOutputDirectoryRoot="model-output",
                                  ResultDirectoryNameFormat="%d %b %y - %H%M",
                                  PeripheryOutputFilePrefix="periphery-output-",
                                  NCOutputFilePrefix="nc-output-",
                                  PeripheryConfigurationName="simulation-configuration.yaml",
                                  SummaryPlotFileName="summary-plots.pdf",
                                  ResourceDirectoryName="resources",
                                  StimulusTemplateName="default_stimulus.yaml"
                                  )
# This is the path of __this file__, which we can then base location on
rootPath = os.path.dirname(os.path.abspath(__file__))

元组是不可变的;命名元组具有语义上有意义的索引,现在:
  • 我可以创建多个字典以便在传递数据时知道它们的键
  • 我可以使用已知的文件名和位置编写和检索文件。
  • 重构意味着我只需要在一个地方修改一个魔术字符串。
  • 即使模块已安装,我也知道我的目录在哪里。
在c#中,有一个或多个“Constants”类填充了“public static const string Foo =“some magic string value”;这样的内容是相当普遍的实践,所以我试图在这里重新创建这种方法。
我目前在base.py中有4个这样的“namedtuples”,这似乎已经接近有太多 - 但我不需要比这更多。它们都在语义上不同 - 我根据用法关联将常量分组。
这是普遍的做法吗?

这并不常见。虽然不常见,但可能会引起兴趣,请参阅问题 Can I prevent modifying an object in Python? - martineau
2个回答

3
多年来,我发现实际答案是attrs。特别地,驳斥我使用namedtuple的想法的是this explainer。现在,我会用冻结的槽类来表达我最初想要的东西:
import attrs

@attr.s(frozen=True, slots=True)
class ModelParams:
    fs = attr.ib(default=1000)
    ...
# about as close to immutable as you can get.
model_params = ModelParams()

0
这并不是标准做法。对于常量,标准惯例是使用全大写的名称来表明该值为常量,并将其记录为常量。
MODEL_DIRECTORY_LABEL_NAME = ".model-output-root"
DEFAULT_MODEL_OUTPUT_DIRECTORY_ROOT = "model-output"
# etc

你的模块的用户自行修改这些值,风险自负。
如果常量与类自然相关,则可以将其作为类属性而不是模块级全局变量,但通常不会创建一个仅用于分组此类值的类。

1
我还没有创建一个类,但是我已经将所有的全局常量分组到一个文件中。对于这个应用程序,我是自己的主要用户 - 但是,正如显而易见的那样,我对于仅仅声明字符串有一些残留的疑虑。 - gvoysey

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