用于字符串内部API的Pythonic方法



问题

有" pythonic"(即规范,官方,PEP8批准等)重新使用python内部(和外部)API中的字符串文字?


背景

例如,我正在使用一些(不一致的)JSON处理代码(数千行),其中有各种各样的json' struct s&quot我们组装,解析等。代码评论期间出现的一个反复出现的问题之一是使用相同的内部参数名称,引起混乱并最终导致错误出现的JSON struct s,例如:

pathPacket['src'] = "/tmp"
pathPacket['dst'] = "/home/user/out"
urlPacket['src'] = "localhost"
urlPacket['dst'] = "contoso"

这两个(示例)数据包具有数十个相同命名的字段,但它们代表了非常不同类型的数据。此实施没有代码解用理由。人们通常会使用代码完成引擎来吸引JSON struct的成员,这最终导致由于导致功能性问题而导致功能性问题的字符串文字而导致难以解决的问题,而不是较早地触发错误。当我们不得不更改这些API时,要寻找字符串文字需要很多时间才能找出哪些JSON struct使用哪些字段。


问题 - redux

python社区的成员中,有更好的方法吗?如果我在C++中这样做,那么较早的示例将是:

const char *JSON_PATH_SRC = "src";
const char *JSON_PATH_DST = "dst";
const char *JSON_URL_SRC = "src";
const char *JSON_URL_DST = "dst";
// Define/allocate JSON structs
pathPacket[JSON_PATH_SRC] = "/tmp";
pathPacket[JSON_PATH_DST] = "/home/user/out";
urlPacket[JSON_URL_SRC] = "localhost";
urlPacket[JSON_URL_SRC] = "contoso";

我的最初方法是:

  • 使用 abc来制作无法初始化为对象的抽象基类,并使用读取仅读取常数。
  • 将该类用作整个项目的通用模块。
  • 通过使用这些常数,我可以减少猴子绘制错误的机会,因为如果插入错误,符号将不存在,而字符串字面的错别字可以通过代码评论滑倒。

我提出的解决方案(对建议/批评开放)

from abc import ABCMeta
class Custom_Structure:
    __metaclass__ = ABCMeta
    @property
    def JSON_PATH_SRC():
        return self._JSON_PATH_SRC
    @property
    def JSON_PATH_DST():
        return self._JSON_PATH_DST
    @property
    def JSON_URL_SRC():
        return self._JSON_URL_SRC
    @property
    def JSON_URL_DST():
        return self._JSON_URL_DST

通常这样做的方式是:

JSON_PATH_SRC = "src"
JSON_PATH_DST = "dst"
JSON_URL_SRC = "src"
JSON_URL_DST = "dst"

pathPacket[JSON_PATH_SRC] = "/tmp"
pathPacket[JSON_PATH_DST] = "/home/user/out"
urlPacket[JSON_URL_SRC] = "localhost"
urlPacket[JSON_URL_SRC] = "contoso"

上案例表示"常数"是它的发展方式。您将在标准库中看到此内容,甚至在PEP8中推荐它:

常数通常在模块级别定义,并以所有内容书写 大写字母,分开单词。示例包括 MAX_OVERFLOWTOTAL

python没有真正的常数,没有它们,它似乎已经幸免于难。如果您会在使用属性的ABCmeta中将其包裹起来更舒服,请继续。确实,我很确定abc.ABCmeta不会不是防止对象初始化。确实,如果 dod ,您对property的使用将无效!property对象属于类,但要从一个实例访问。对我来说,它看起来像是很多rigamarole,几乎没有收获。

我认为制作常数的最简单方法只是将它们设置为模块中的变量(而不是修改它们)。

JSON_PATH_SRC = "src"
JSON_PATH_DST = "dst"
JSON_URL_SRC = "src"
JSON_URL_DST = "dst"

那么,如果您需要从另一个模块中引用它们,它们已经为您命名。

>>> that_module.JSON_PATH_SRC
'src'
>>> that_module.JSON_PATH_DST
'dst'
>>> that_module.JSON_URL_SRC
'src'
>>> that_module.JSON_URL_DST
'dst'

创建一堆常数的最简单方法是将它们放入模块中,并根据需要导入它们。例如,您可以使用

constants.py模块
JSON_PATH_SRC = "src"
JSON_PATH_DST = "dst"
JSON_URL_SRC = "src"
JSON_URL_DST = "dst"

您的代码将执行

之类的事情
from constants import JSON_URL_SRC
...
urlPacket[JSON_URL_SRC] = "localhost"

如果您想要更好定义的常数分组,则可以将它们粘贴到专用的软件包中的单独模块中,以便您像constants.json.url.DST一样访问它们,也可以使用Enum s。Enum类允许您将相关的常数集分组为一个名称空间。您可以像这样编写一个模块constants.py

from enum import Enum
class JSONPath(Enum):
    SRC = 'src'
    DST = 'dst'
class JSONUrl(Enum):
    SRC = 'src'
    DST = 'dst'

from enum import Enum
class JSON(Enum):
    PATH_SRC = 'src'
    PATH_DST = 'dst'
    URL_SRC = 'src'
    URL_DST = 'dst'

您如何确切地将常数分开取决于您。您可以有一个巨大的枚举,每个类别或两者之间的东西。您将在代码中访问:

from constants import JSONURL
...
urlPacket[JSONURL.SRC.value] = "localhost"

from constants import JSON
...
urlPacket[JSON.URL_SRC.value] = "localhost"

最新更新