1

问题

python是否有“pythonic”(即规范、官方、PEP8 批准等)方式在内部(和外部)API中重用字符串文字?


背景

例如,我正在使用一些(不一致的)JSON 处理代码(数千行),其中有各种struct我们组装、解析等的 JSON “s”。代码审查期间出现的反复出现的问题之一是不同的 JSON structs 使用相同的内部参数名称,导致混淆并最终导致出现错误,例如:

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

这两个(示例)数据包具有数十个相同名称的字段,但它们代表非常不同类型的数据。这个实现没有代码重用的理由。人们通常使用代码完成引擎来获取 JSON 的成员struct,这最终会导致难以调试的问题,因为错误输入的字符串文字会导致功能问题,并且不会更早地触发错误。当我们必须更改这些 API 时,需要花费大量时间来寻找字符串文字以找出哪些 JSONstruct使用哪些字段。


问题 - 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
4

3 回答 3

4

通常这样做的方式是:

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不会阻止对象初始化。确实,如果确实如此,您的使用property将无法正常工作!property对象属于 class,但旨在从实例访问。对我来说,这看起来就像是很多琐碎的收获。

于 2017-12-21T19:18:26.100 回答
3

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

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'
于 2017-12-21T19:19:44.140 回答
1

创建一堆常量的最简单方法是将它们放入一个模块中,并根据需要导入它们。例如,你可以有一个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例如允许您访问它们,或者您可以使用Enums. 该类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"
于 2017-12-21T19:28:04.243 回答