我正在尝试实现dict
数据结构的自定义行为。
我想覆盖__getitem__
并在将值返回给用户之前对值应用某种正则表达式。
片段:
class RegexMatchingDict(dict):
def __init__(self, dct, regex, value_group, replace_with_group, **kwargs):
super().__init__(**kwargs)
self.replace_with_group = replace_with_group
self.value_group = value_group
self.regex_str = regex
self.regex_matcher = re.compile(regex)
self.update(dct)
def __getitem__(self, key):
value: Union[str, dict] = dict.__getitem__(self, key)
if type(value) is str:
match = self.regex_matcher.match(value)
if match:
return value.replace(match.group(self.replace_with_group), os.getenv(match.group(self.value_group)))
return value # I BELIEVE ISSUE IS HERE
这适用于单个索引级别(即dict[key]
)。但是,当尝试对其进行多索引时(即dict[key1][key2]
),会发生的情况是第一个索引级别从我的类返回一个对象。但是,其他级别调用__getitem__
中的默认dict
,它不执行我的自定义行为。我怎样才能解决这个问题?
MCVE:
前面提到的代码将正则表达式应用于值,并将其转换为相应的环境变量的值,如果它是字符串(即,dict中的最低级别)
dictionary = {"KEY": "{ENVIRONMENT_VARIABLE}"}
custom_dict = RegexMatchingDict(dictionary, r"((.*({(.+)}).*))", 4 ,3)
让我们设置一个名为ENVIRONMENT_VARIABLE
的env变量设置为1
。
import os
os.environ["ENVIRONMENT_VARIABLE"] = "1"
在这种情况下,你的代码完全正常
custom_dict["KEY"]
并且返回的值将是:
{"KEY": 1}
但是,如果我们有一个多级索引
dictionary = {"KEY": {"INDEXT_KEY": "{ENVIRONMENT_VARIABLE}"}
custom_dict = RegexMatchingDict(dictionary, r"((.*({(.+)}).*))", 4 ,3)
custom_dict["KEY"]["INDEX_KEY"]
这会回来
{ENVIRONMENT_VARIABLE}
P. S.有许多类似的问题,但它们都(可能)解决了顶级索引问题。
正如您所说,问题出现在代码的最后一行。
if type(value) is str:
...
else:
return value # I BELIEVE ISSUE IS HERE
这是返回一个dict
。但是你想要返回一个RegexMatchingDict
,它将知道如何处理第二级索引。因此,如果它是value
而不是返回dict
,将其转换为RegexMatchingDict
并返回它。然后,当调用__getitem__()
执行第二级索引时,您将获得您的版本而不是标准版本。
像这样的东西:
return RegexMatchingDict(value, self.regex_str, self.value_group, self.replace_with_group)
这复制了第一级别的其他参数,因为很难看出第二级别如何不同。
在您的示例中,您的二级字典是正常的dict
,因此不使用您的自定义__getitem__
方法。
下面的代码显示了如何使用内部自定义dict
:
sec_level_dict = {"KEY": "{ENVIRONMENT_VARIABLE}"}
sec_level_custom_dict = RegexMatchingDict(sec_level_dict, r"((.*({(.+)}).*))", 4 ,3)
dictionary = {"KEY": sec_level_custom_dict}
custom_dict = RegexMatchingDict(dictionary, r"((.*({(.+)}).*))", 4 ,3)
print(custom_dict["KEY"]["KEY"])
如果你想自动化它并在自定义dict
中转换所有嵌套的dict
,你可以按照这种模式自定义__setitem__
:
class CustomDict(dict):
def __init__(self, dct):
super().__init__()
for k, v in dct.items():
self[k] = v
def __getitem__(self, key):
value = dict.__getitem__(self, key)
print("Dictionary:", self, "key:", key, "value:", value)
return value
def __setitem__(self, key, value):
if isinstance(value, dict):
dict.__setitem__(self, key, self.__class__(value))
else:
dict.__setitem__(self, key, value)
a = CustomDict({'k': {'k': "This is my nested value"}})
print(a['k']['k'])