我正在尝试实现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
的环境变量设置为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.有许多相似问题,但它们都(可能)涉及顶级索引。
答案 0 :(得分:1)
您自己说的问题出在代码的最后一行。
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)
由于很难看到第二层的差异,因此这会复制第一层的其他参数。
答案 1 :(得分:0)
在您的示例中,二级字典是普通 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'])