字符串内部 API 的 Pythonic 方法
Pythonic approach to internal API for strings
问题
是否有“pythonic”(即规范的、官方的、PEP8 批准的等)方法在 python
内部(和外部)API 中重用字符串文字?
背景
例如,我正在处理一些(不一致的)JSON-处理代码(数千行),其中有各种 JSON “struct
s” 我们 assemble、parse 等。代码审查期间反复出现的问题之一是不同的 JSON struct
使用相同的内部参数名称,导致混淆并最终导致错误出现,例如:
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
创建一个抽象基础class,不能被初始化为一个对象,并用填充它只读 常量。
- 在我的项目中使用 class 作为通用模块。
- 通过使用这些常量,我可以减少猴子修补错误的可能性,因为如果拼写错误,符号将不存在,而字符串文字拼写错误可以通过代码审查。
我提出的解决方案(对advice/criticism开放)
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"
大写表示 "constants" 就是这样。你会在标准库中看到它,它甚至在 PEP8:
中被推荐
Constants are usually defined on a module level and written in all
capital letters with underscores separating words. Examples include
MAX_OVERFLOW
and TOTAL
.
Python 没有真正的常数,而且它似乎没有它们也能存活下来。如果将其包装在使用 ABCmeta
和属性的 class 中会让您感觉更舒服,请继续。事实上,我很确定 abc.ABCmeta
不会 不会 阻止对象初始化。的确,如果做了,你使用property
就不行了! property
个对象 属于 class,但要从实例访问。对我来说,它看起来就像是大量的 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
秒。 Enum
class 允许您将相关的常量集分组到一个命名空间中。你可以这样写一个模块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"
问题
是否有“pythonic”(即规范的、官方的、PEP8 批准的等)方法在 python
内部(和外部)API 中重用字符串文字?
背景
例如,我正在处理一些(不一致的)JSON-处理代码(数千行),其中有各种 JSON “struct
s” 我们 assemble、parse 等。代码审查期间反复出现的问题之一是不同的 JSON struct
使用相同的内部参数名称,导致混淆并最终导致错误出现,例如:
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
创建一个抽象基础class,不能被初始化为一个对象,并用填充它只读 常量。 - 在我的项目中使用 class 作为通用模块。
- 通过使用这些常量,我可以减少猴子修补错误的可能性,因为如果拼写错误,符号将不存在,而字符串文字拼写错误可以通过代码审查。
我提出的解决方案(对advice/criticism开放)
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"
大写表示 "constants" 就是这样。你会在标准库中看到它,它甚至在 PEP8:
中被推荐Constants are usually defined on a module level and written in all capital letters with underscores separating words. Examples include
MAX_OVERFLOW
andTOTAL
.
Python 没有真正的常数,而且它似乎没有它们也能存活下来。如果将其包装在使用 ABCmeta
和属性的 class 中会让您感觉更舒服,请继续。事实上,我很确定 abc.ABCmeta
不会 不会 阻止对象初始化。的确,如果做了,你使用property
就不行了! property
个对象 属于 class,但要从实例访问。对我来说,它看起来就像是大量的 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
秒。 Enum
class 允许您将相关的常量集分组到一个命名空间中。你可以这样写一个模块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"