使用变量作为字典键集 [英] Use Variable As Dictionary Key Set

查看:69
本文介绍了使用变量作为字典键集的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将JSON文件解析为字典,例如下面的JSON数据

I parse a JSON file to a dictionary, example JSON data below

 {
    "environmental": {
      "temprature": {
           "test" : "temprature",
           "unit": "c", 

           "now": 12.65,
           "now_timestamp": "10-06-2019 08:02:18", 

           "min": "12.5", 
           "min_timestamp": "03-06-2019 07:40:02", 

           "max": "32.84", 
           "max_timestamp": "03-06-2019 04:30:03"
      }
    }
}

我想使用列表元组或字符串作为字典键来检索值或设置值.

I would like to either retrieve a value or set a value using a list tuple or string as the dictionary key.

var_lst_key = ["environmental", "temprature", "now"]
var_dict_x[var_lst_key] = "x"

print(var_dict_x[var_lst_key])

推荐答案

第1部分:做到简单:使用函数

嵌套查找非常容易.您遍历键,然后继续用您当前正在查看的键上的值替换您要寻找的对象:

Part 1: Doing it the easy way: using functions

A nested lookup is pretty easy to do. You iterate over the keys, and keep replacing the object you're looking into with the value at the key you're currently looking at:

def nested_get(obj, keys):
    for key in keys:
        obj = obj[key]
    return obj

def nested_set(obj, keys, value):
    for key in keys[:-1]:
        # Drill down until the penultimate key
        obj = obj[key]
    # Set value of last key
    obj[keys[-1]] = value

要运行此命令:

jstr = """{ "environmental": {
      "temprature": {
           "test" : "temprature",
           "unit": "c", 

           "now": 12.65,
           "now_timestamp": "10-06-2019 08:02:18", 

           "min": "12.5", 
           "min_timestamp": "03-06-2019 07:40:02", 

           "max": "32.84", 
           "max_timestamp": "03-06-2019 04:30:03"
      }
}}"""

jobj = json.loads(jstr)

var_lst_key = ["environmental", "temprature", "now"]
nested_lookup(jobj, var_lst_key) # Returns 12.65

invalid_keys = ["environmental", "temprature", "hello"] 
nested_lookup(jobj, invalid_keys) # throws KeyError 'hello'

nested_set(jobj, var_lst_key, "HELLO!")
nested_lookup(jobj, var_lst_key) # Returns HELLO!

第2部分:花哨的方法:使用派生类

现在,如果您真的要使用 dict [key] = value 语法,则必须扩展 dict 类重写其 __ getitem __() __ setitem __()方法.

Part 2: Doing it the fancy way: using a derived class

Now if you really want to use the dict[key] = value syntax, you're going to have to extend the dict class to override its __getitem__() and __setitem__() methods.

class NestedLookupDict(dict):
    def __init__(self, *args, **kwargs):
        super(type(self), self).__init__(*args, **kwargs)
        self.insert_missing_keys = True


    def __getitem__(self, indices):
        # Get the super dictionary for easy lookup
        obj = self
        for i in indices:
            obj = dict.__getitem__(obj, i)
        return obj
    
    def __setitem__(self, indices, value):
        # Get the base dictionary
        obj = self
        # Drill down until the penultimate key
        for i in indices[:-1]:
            # Insert a new dict if a key is missing
            if self.insert_missing_keys and not dict.__contains__(obj, i):
                dict.__setitem__(obj, i, dict())
            obj = dict.__getitem__(obj, i)
        # Set the value at the final key
        dict.__setitem__(obj, indices[-1], value)

要使用此功能,让我们像以前一样使用从字符串中解析出的json对象:

To use this, let's use the json object parsed from the string like before:

# jobj = {... something ...}
nested_dict = NestedLookupDict(jobj)

print(nested_dict[var_lst_key]) # Prints 12.65

nested_dict[var_lst_key] = "HELLO!"

print(nested_dict[var_lst_key]) # Prints HELLO!

nested_dict.insert_missing_keys 设置为 True (默认情况下)时, __ setitem __()方法会在需要时添加缺少的字典.

When nested_dict.insert_missing_keys is set to True (by default), the __setitem__() method adds missing dictionaries if required.

newkey = ["environmental", "temprature", "newkey"]
nested_dict[newkey] = "NEWKEY!!!"
print(nested_dict[newkey]) # Prints NEWKEY!!!

newkey2 = ["environmental", "temprature", "nested", "newkey"]
nested_dict[newkey2] = "NESTEDNEWKEY!!!"
print(nested_dict[newkey2]) # Prints NESTEDNEWKEY!!!

在所有这些操作的最后,您可以将对象转储到json来查看其外观:

At the end of all this, you can dump the object to json to see what it looks like:

print(json.dumps(nested_dict))

# Output: 
{
    "environmental": {
        "temprature": {
            "test": "temprature",
            "unit": "c",
            "now": "HELLO!",
            "now_timestamp": "10-06-2019 08:02:18",
            "min": "12.5",
            "min_timestamp": "03-06-2019 07:40:02",
            "max": "32.84",
            "max_timestamp": "03-06-2019 04:30:03",
            "newkey": "NEWKEY!!!",
            "nested": {
                "newkey": "NESTEDNEWKEY!!!"
            }
        }
    }
}


第3部分:过度杀戮,但是哦!如此有趣的代码:丰富了NestedLookupDict

其他功能,因此您几乎可以像 dict 一样使用它:

  • 使用 del nested_dict [key]
  • 删除键
  • 检查键是否与nested_dict
  • 中的 key存在
  • nested_dict.get(键,默认值) key 不存在的情况下吸收 KeyError ,并返回 default
  • 进行类型检查:它们现在必须是 list tuple
  • Delete keys using del nested_dict[key]
  • Check if keys exist with key in nested_dict
  • nested_dict.get(key, default) absorbs the KeyError if key doesn't exist, and returns default
  • Implemented a type check on keys: they must be list or tuple now

怪癖:

  • 由于实现 __ getitem __()的方式, nested_dict [empty_list] 返回对 nested_dict 的引用(本身).如果这是一件坏事,可以添加对空键的检查.但是,我认为以这种方式保留它不会带来任何问题.此怪癖的一些后果:
    • 要使此行为与 __ contains __()的工作方式保持一致, __ contains __()函数将为空的 key 返回 True ./code>.nested_list中的 []:= True
    • 根据定义,您不能设置 nested_list [[]] .这会引发ValueError
    • Because of the way __getitem__() is implemented, nested_dict[empty_list] returns a reference to nested_dict (itself). If this is a bad thing, a check for empty keys could be added. However, I don't see any problems coming from leaving it this way. Some consequences of this quirk:
      • To keep this behavior consistent with how __contains__() works, the __contains__() function returns True for empty key. [] in nested_list := True
      • You cannot, by definition, set nested_list[[]]. That throws a ValueError
      class NestedLookupDict(dict):
          def __init__(self, *args, **kwargs):
              super(type(self), self).__init__(*args, **kwargs)
              self.insert_missing_keys = True
      
          def check_keys(self, keys):
              if not isinstance(keys, (list, tuple)):
                  raise TypeError("keys must be of type list or tuple")
      
          def get(self, keys, default=None):
              self.check_keys(keys)
              try:
                  return self.__getitem__(keys)
              except KeyError:
                  return default
      
          def __contains__(self, keys):
              self.check_keys(keys)
              if not keys: return True # nested_dict contains the key [] = itself
              if len(keys) > 1:
                  return self.__getitem__(keys[:-1]).__contains__(keys[-1])
              else:
                  return dict.__contains__(self, keys[0])
      
          def __delitem__(self, keys):
              self.check_keys(keys)
              obj = self
              for i in keys[:-1]:
                  obj = dict.__getitem__(obj, i)
              dict.__delitem__(obj, keys[-1])
      
          def __getitem__(self, keys):
              self.check_keys(keys)
              # Get the super dictionary for easy lookup
              obj = self
              for i in keys:
                  obj = dict.__getitem__(obj, i)
              return obj
          
          def __setitem__(self, keys, value):
              self.check_keys(keys)
              if not keys: raise ValueError("keys cannot be empty")
              # Get the base dictionary
              obj = self
              # Drill down until the penultimate key
              for i in keys[:-1]:
                  # Insert a new dict if a key is missing
                  if self.insert_missing_keys and not dict.__contains__(obj, i):
                      dict.__setitem__(obj, i, dict())
                  obj = dict.__getitem__(obj, i)
              # Set the value at the final key
              dict.__setitem__(obj, keys[-1], value)
      

      这篇关于使用变量作为字典键集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆