如何清除特定键的动态python字典?
这一个只是够迟钝的,没有一个典型的答案是冒泡到顶部 我正在使用的工具的性质决定了我们使用MongoDB来存储大约25种不同工具的“设置”。每个工具都有自己的设置模式,因此每个文档都是不同的,但它们都存储在相同的集合中,并在由json模式绘制的相同编辑页面上进行编辑 由于不知道字典的模式,我正在努力找出如何迭代和清理数据,特别是删除密码 考虑到下面的字典,并且知道其他dict可能有不同的模式,我如何遍历dict中的每一项并创建一个副本,除了删除任何key==“password”之外都是相同的 因此: 应导致:如何清除特定键的动态python字典?,python,dictionary,Python,Dictionary,这一个只是够迟钝的,没有一个典型的答案是冒泡到顶部 我正在使用的工具的性质决定了我们使用MongoDB来存储大约25种不同工具的“设置”。每个工具都有自己的设置模式,因此每个文档都是不同的,但它们都存储在相同的集合中,并在由json模式绘制的相同编辑页面上进行编辑 由于不知道字典的模式,我正在努力找出如何迭代和清理数据,特别是删除密码 考虑到下面的字典,并且知道其他dict可能有不同的模式,我如何遍历dict中的每一项并创建一个副本,除了删除任何key==“password”之外都是相同的 因此
{
"_enabled": true,
"instances": [
{
"isdefault": true,
"name": "dev",
"url": "http://dev.example.com",
"user": "buffy"
},
{
"isdefault": false,
"name": "prod",
"url": "http://prod.example.com",
"user": "spike"
},
{
"isdefault": false,
"name": "qa",
"url": "http://prod.example.com",
"user": "willow"
}
],
"label": "MyServers"
}
首先深度复制dict,然后捕获所有字典并删除密码密钥:
from copy import deepcopy
def remove_pass(v):
if isinstance(v, dict):
if "password" in v:
del v["password"]
for ele in v.values():
remove_pass(ele)
elif isinstance(v, Iterable) and not isinstance(v, basestring):
for ele in v:
remove_pass(ele)
from pprint import pprint as pp
d = deepcopy(d)
for v in d.values():
remove_pass(v)
输入:
{'_enabled': 'true',
'foo': {'isdefault': 'false',
'name': 'qa',
'nested': {'password': 'nested'},
'password': 'dasddf',
'url': 'http://prod.example.com',
'user': 'willow'},
'instances': [{'isdefault': 'true',
'name': 'dev',
'password': 'abc123',
'url': 'http://dev.example.com',
'user': 'buffy'},
{'isdefault': 'false',
'name': 'prod',
nested': {'more_nesting': {'even_more_nesting': ({'password': 'foobar'},
{'password': 'foob'}),
'password': 'bar'},
'password': 'xxxxx',
'url': 'http://prod.example.com',
'user': 'spike'},
{'isdefault': 'false',
'name': 'qa',
'password': 'dasddf',
'url': 'http://prod.example.com',
'user': 'willow'}],
'label': 'MyServers'}
输出:
{'_enabled': 'true',
'foo': {'isdefault': 'false',
'name': 'qa',
'nested': {},
'url': 'http://prod.example.com',
'user': 'willow'},
'instances': [{'isdefault': 'true',
'name': 'dev',
'url': 'http://dev.example.com',
'user': 'buffy'},
{'isdefault': 'false',
'name': 'prod',
'nested': {'more_nesting': {'even_more_nesting': ({}, {})}},
'url': 'http://prod.example.com',
'user': 'spike'},
{'isdefault': 'false',
'name': 'qa',
'url': 'http://prod.example.com',
'user': 'willow'}],
'label': 'MyServers'}
如果您知道每个数据的结构(即,在数组/字典的什么深度处需要“密码”键),这将很简单。您只需在列表项和字典中循环查找“密码”键 如果每个设置字典的结构真的不可预测,那么您必须拼凑出一个解决方案。在这种情况下,我所做的是将JSON转储到字符串中,使用正则表达式删除/隔离我感兴趣的数据,然后将字符串加载回结构化JSON 大概是这样的: 导入json,重新
raw_data = """{
"_enabled": true,
"instances": [
{
"isdefault": true,
"name": "dev",
"password": "abc123",
"url": "http://dev.example.com",
"user": "buffy"
},
{
"isdefault": false,
"name": "prod",
"password": "xxxxx",
"url": "http://prod.example.com",
"user": "spike"
},
{
"isdefault": false,
"name": "qa",
"password": "dasddf",
"url": "http://prod.example.com",
"user": "willow"
}
],
"label": "MyServers"
}"""
# I load and then dump my raw_data just to iron out any inconsistencies
# in formatting before applying regex. i.e., inconsistent use of " instead of '
structured_data = json.loads(raw_data)
dumped_data = json.dumps(structured_data)
scrubbed = re.sub(r'"password": ".*?",', '', dumped_data)
structured_scrubbed = json.loads(scrubbed)
结果:
structured_scrubbed = {'_enabled': True,
'instances': [{'isdefault': True,
'name': 'dev',
'url': 'http://dev.example.com',
'user': 'buffy'},
{'isdefault': False,
'name': 'prod',
'url': 'http://prod.example.com',
'user': 'spike'},
{'isdefault': False,
'name': 'qa',
'url': 'http://prod.example.com',
'user': 'willow'}],
'label': 'MyServers'}
我使用常规函数
getpath
在嵌套字典中查找特定键的路径。您可以使用它继续查找“密码”密钥的所有路径,然后更改或删除它。这适用于json字符串的所有格式/模式
def getPaths(dictionary, searchKey):
'''
generator to get all paths for the key in the nested dictionary
'''
for k, v in dictionary.items():
if k == searchKey :
yield []
elif isinstance(v, dict):
# if the value if dict, go in recursively and yield the path
for subkey in getPaths(v, searchKey):
yield [k]+subkey
elif isinstance(v, list):
# if value is a list, for each element in the list, go in recursively and yield the path
for i, item in enumerate(v):
if isinstance(item, dict):
for subkey in getPaths(item, searchKey):
yield [k]+[i]+subkey
jsonstring = """{
"_enabled": true,
"instances": [
{
"isdefault": true,
"name": "dev",
"password": "abc123",
"url": "http://dev.example.com",
"user": "buffy"
},
{
"isdefault": false,
"name": "prod",
"password": "xxxxx",
"url": "http://prod.example.com",
"user": "spike"
},
{
"instance2": {
"isdefault": false,
"name": "qa",
"password": "dasddf",
"url": "http://prod.example.com",
"user": "willow"
}
}
],
"label": "MyServers"
}"""
import json
jsonObj = json.loads(jsonstring)
paths = getPaths(jsonObj , "password")
for path in paths:
print('path:', path)
结果:
>>> path: ['instances', 0]
>>> path: ['instances', 1]
>>> path: ['instances', 2, 'instance2']
假设您只想检查列表或字典的容器,并从包含
key=“password”
你被困在哪里?你试了什么?看起来您只需在实例中循环dict并删除密码键/值对……等等,这是python字典吗?它看起来像是json或其他东西……是的,它看起来像是json对mee来说是令人困惑的,因为您谈论的是动态模式。如果每个dict的结构如此不同,以至于你永远不知道会遇到什么,那么无论我们讨论的是什么方法或语言,你都无法开发算法。然而,我怀疑aschmid有答案:
对于原始目录中的子目录['instances']:如果子目录中的'password':del subdct['password']
甚至比查看目录中是否有'password',然后删除该键/值对是d.pop('password',None)
@bgporter更容易,查找是0(1),这不是一个真正的问题,甚至不考虑执行时间,只是代码的清晰性。我想是品味的问题。@bgporter,在这种情况下,我更担心的是如何获得灵活且有效的代码,而不是其他任何东西,因为我需要付出额外的努力,并用更多的嵌套来证明这一点。我稍微修改了一下,只是将密码字段的值设置为“”,而不是将其删除(这样pop就不会工作了),但这正是我所需要的,而且很容易就实现了。(有时我们会把事情搞得过于复杂!)谢谢!
>>> path: ['instances', 0]
>>> path: ['instances', 1]
>>> path: ['instances', 2, 'instance2']
#first copy the structure
new_data = copy.deepcopy(data)
#this is a recursive function.
#Heavily nested structures may fail due to recursion limit
def clean_hierarchy(ele):
#lists may contain dictionaries, so clean theses entries
if isinstance(ele,list):
for val in ele:
clean_hierarchy(val)
if isinstance(ele,dict):
#remove possible password entry
if "password" in ele:
ele.pop("password",None)
#dictionary may contain more dictionaries. Rinse and repeat!
for val in ele.values():
clean_hierarchy(val)
clean_hierarchy(new_data)