如何从 Python 中的字典列表中获取所有一个键?
How do I get all of one key from a list of dicts in Python?
我有一个很大的 JSON 文件,如下所示:
{
"data" : [
{"album": "I Look to You", "writer": "Leon Russell", "artist": "Whitney Houston", "year": "2009", "title": "\"A Song for You\""},
{"album": "Michael Zager Band", "writer": "Michael Zager", "artist": "Whitney Houston", "year": "1983", "title": "\"Life's a Party\""},
{"album": "Paul Jabara & Friends", "writer": "Paul Jabara", "artist": "Whitney Houston", "year": "1978", "title": "\"Eternal Love\""},
...
...我正在尝试制作一个非常简单的 API 来获取不同的值。现在我可以相当容易地获得 localhost/data/1/title
例如获得第一个标题值,但我想通过 localhost/titles
或其他方式获得 all 的标题。我将如何修改此处的 do_GET
方法以添加此类功能?
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
path = self.path[1:]
components = string.split(path, '/')
node = content
for component in components:
if len(component) == 0 or component == "favicon.ico":
continue
if type(node) == dict:
node = node[component]
elif type(node) == list:
node = node[int(component)]
self.wfile.write(json.dumps(node))
return
这是一个非常模糊的想法,但我希望这个概念能被理解。
在此示例中,如果 url 不以 'data' 开头,它将使用 url 中指定的组件映射数据集合(如 'titles' ).
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
path = self.path[1:]
components = string.split(path, '/')
if components and components[0] != 'data':
node = map(lambda x: x.get(components[0]), content)
else:
node = content
for component in components:
if len(component) == 0 or component == "favicon.ico":
continue
if type(node) == dict:
node = node[component]
elif type(node) == list:
node = node[int(component)]
self.wfile.write(json.dumps(node))
return
这里的答案将遵循您当前的动态 URL 模式,而不会发生重大架构更改或要求。
在这里,我使用 "all" 替换 url 模式中的给定数字索引,因为我觉得这更好地代表了 data/[item(s)]/[attribute]
[=17= 的范例]
以下是一些 URLs 和示例输出:
/data/1/album
=> "Michael Zager Band"
/data/0/title
=> "A Song for You"
/data/all/title
=> ["A Song for You", "Life's a Party", "Eternal Love"]
/data/all/year
=> ["2009", "1983", "1978"]
/data/1
=> {"album": "Michael Zager Band", "title": "Life's a Party", "writer": "Michael Zager", "year": "1983", "artist": "Whitney Houston"}
PS - 我稍微改变了架构,使用递归,我认为这更好地遵循你想要做的事情。
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
path = self.path[1:]
components = string.split(path, '/')
node = parse_node(content, components)
self.wfile.write(json.dumps(node))
return
def parse_node(node, components):
# For a valid node and component list:
if node and len(components) and components[0] != "favicon.ico":
# Dicts will return parse_node of the top-level node component found,
# reducing the component list by 1
if type(node) == dict:
return parse_node(node.get(components[0], None), components[1:])
elif type(node) == list:
# A list with an "all" argument will return a full list of sub-nodes matching the rest of the URL criteria
if components[0] == "all":
return [parse_node(n, components[1:]) for n in node]
# A normal list node request will work as it did previously
else:
return parse_node(node[int(components[0])], components[1:])
else:
return node
# Handle bad URL
return None
我认为您 运行 遇到了麻烦,因为您正试图遍历路径组件以确定要做什么。这是一个有点复杂的解决问题的方法。
我会首先定义您希望 API 支持的 "routes" 或 "actions",然后编写代码来处理每个。这就是大多数网络框架的运作方式(例如 django's URL patterns or flask's routes)。在您的代码中使用相同的模式非常简单。
因此,根据您的描述,您似乎想要两条路线:
/data/{id}/{attr} - look up the value of `attr` for the given `id`
/{attr} - search all items for `attr`
我还将简化 "title" 与 "titles" 的对比,并且只使用单数形式,因为复数形式可能会带来更多麻烦,而不是它的价值。但如果你真的想这样做,有些图书馆可以提供帮助(例如 this one)。
一旦我们决定 URL 将遵循这两种模式,就很容易检查组件是否与它们匹配。请注意,我在这里简化了您的代码以获取它 运行 因为我不确定 do_GET
是如何调用的,或者 self
是什么:
import json
JSON = {
"data" : [
{"album": "I Look to You", "writer": "Leon Russell", "artist": "Whitney Houston", "year": "2009", "title": "\"A Song for You\""},
{"album": "Michael Zager Band", "writer": "Michael Zager", "artist": "Whitney Houston", "year": "1983", "title": "\"Life's a Party\""},
{"album": "Paul Jabara & Friends", "writer": "Paul Jabara", "artist": "Whitney Houston", "year": "1978", "title": "\"Eternal Love\""},
]
}
def do_GET(path):
path = path[1:]
components = path.split('/')
if components[0] == 'favicon.ico':
return "favicon response"
elif len(components) == 0 or not path:
return "error response"
elif len(components) == 3 and components[0] == "data":
#/data/{id}/{attr} - look up the value of `attr` for the given `id`
key, item_id, attr = components
item_id = int(item_id)
return json.dumps(JSON[key][item_id][attr])
elif len(components) == 1:
#/{attr} - search all items for `attr`
attr = components[0]
out = []
for k in JSON:
for d in JSON[k]:
if attr in d:
out.append(d[attr])
return json.dumps(out)
else:
return "unknown response"
return json.dumps(node)
if __name__ == "__main__":
urls = [
"/data/1/title",
"/title",
"/some_missing_attr",
"/favicon.ico",
"/",
]
for u in urls:
print u, "->", do_GET(u)
输出:
/data/1/title -> "\"Life's a Party\""
/title -> ["\"A Song for You\"", "\"Life's a Party\"", "\"Eternal Love\""]
/some_missing_attr -> []
/favicon.ico -> favicon response
/ -> error response
除非您真的想在任意 JSON 中进行任意嵌套查找,否则这应该会很好地工作。如果是这种情况,那么我认为您建议的 URL 不会起作用,您怎么知道“/titles”应该搜索所有元素而“/data”会查找一个元素?如果您真的想这样做,我会在 google 中搜索 "JSON query language",看看您可以重复使用哪些项目或从中获得灵感。
我有一个很大的 JSON 文件,如下所示:
{
"data" : [
{"album": "I Look to You", "writer": "Leon Russell", "artist": "Whitney Houston", "year": "2009", "title": "\"A Song for You\""},
{"album": "Michael Zager Band", "writer": "Michael Zager", "artist": "Whitney Houston", "year": "1983", "title": "\"Life's a Party\""},
{"album": "Paul Jabara & Friends", "writer": "Paul Jabara", "artist": "Whitney Houston", "year": "1978", "title": "\"Eternal Love\""},
...
...我正在尝试制作一个非常简单的 API 来获取不同的值。现在我可以相当容易地获得 localhost/data/1/title
例如获得第一个标题值,但我想通过 localhost/titles
或其他方式获得 all 的标题。我将如何修改此处的 do_GET
方法以添加此类功能?
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
path = self.path[1:]
components = string.split(path, '/')
node = content
for component in components:
if len(component) == 0 or component == "favicon.ico":
continue
if type(node) == dict:
node = node[component]
elif type(node) == list:
node = node[int(component)]
self.wfile.write(json.dumps(node))
return
这是一个非常模糊的想法,但我希望这个概念能被理解。
在此示例中,如果 url 不以 'data' 开头,它将使用 url 中指定的组件映射数据集合(如 'titles' ).
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
path = self.path[1:]
components = string.split(path, '/')
if components and components[0] != 'data':
node = map(lambda x: x.get(components[0]), content)
else:
node = content
for component in components:
if len(component) == 0 or component == "favicon.ico":
continue
if type(node) == dict:
node = node[component]
elif type(node) == list:
node = node[int(component)]
self.wfile.write(json.dumps(node))
return
这里的答案将遵循您当前的动态 URL 模式,而不会发生重大架构更改或要求。
在这里,我使用 "all" 替换 url 模式中的给定数字索引,因为我觉得这更好地代表了 data/[item(s)]/[attribute]
[=17= 的范例]
以下是一些 URLs 和示例输出:
/data/1/album
=> "Michael Zager Band"/data/0/title
=> "A Song for You"/data/all/title
=> ["A Song for You", "Life's a Party", "Eternal Love"]/data/all/year
=> ["2009", "1983", "1978"]/data/1
=> {"album": "Michael Zager Band", "title": "Life's a Party", "writer": "Michael Zager", "year": "1983", "artist": "Whitney Houston"}
PS - 我稍微改变了架构,使用递归,我认为这更好地遵循你想要做的事情。
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
path = self.path[1:]
components = string.split(path, '/')
node = parse_node(content, components)
self.wfile.write(json.dumps(node))
return
def parse_node(node, components):
# For a valid node and component list:
if node and len(components) and components[0] != "favicon.ico":
# Dicts will return parse_node of the top-level node component found,
# reducing the component list by 1
if type(node) == dict:
return parse_node(node.get(components[0], None), components[1:])
elif type(node) == list:
# A list with an "all" argument will return a full list of sub-nodes matching the rest of the URL criteria
if components[0] == "all":
return [parse_node(n, components[1:]) for n in node]
# A normal list node request will work as it did previously
else:
return parse_node(node[int(components[0])], components[1:])
else:
return node
# Handle bad URL
return None
我认为您 运行 遇到了麻烦,因为您正试图遍历路径组件以确定要做什么。这是一个有点复杂的解决问题的方法。
我会首先定义您希望 API 支持的 "routes" 或 "actions",然后编写代码来处理每个。这就是大多数网络框架的运作方式(例如 django's URL patterns or flask's routes)。在您的代码中使用相同的模式非常简单。
因此,根据您的描述,您似乎想要两条路线:
/data/{id}/{attr} - look up the value of `attr` for the given `id`
/{attr} - search all items for `attr`
我还将简化 "title" 与 "titles" 的对比,并且只使用单数形式,因为复数形式可能会带来更多麻烦,而不是它的价值。但如果你真的想这样做,有些图书馆可以提供帮助(例如 this one)。
一旦我们决定 URL 将遵循这两种模式,就很容易检查组件是否与它们匹配。请注意,我在这里简化了您的代码以获取它 运行 因为我不确定 do_GET
是如何调用的,或者 self
是什么:
import json
JSON = {
"data" : [
{"album": "I Look to You", "writer": "Leon Russell", "artist": "Whitney Houston", "year": "2009", "title": "\"A Song for You\""},
{"album": "Michael Zager Band", "writer": "Michael Zager", "artist": "Whitney Houston", "year": "1983", "title": "\"Life's a Party\""},
{"album": "Paul Jabara & Friends", "writer": "Paul Jabara", "artist": "Whitney Houston", "year": "1978", "title": "\"Eternal Love\""},
]
}
def do_GET(path):
path = path[1:]
components = path.split('/')
if components[0] == 'favicon.ico':
return "favicon response"
elif len(components) == 0 or not path:
return "error response"
elif len(components) == 3 and components[0] == "data":
#/data/{id}/{attr} - look up the value of `attr` for the given `id`
key, item_id, attr = components
item_id = int(item_id)
return json.dumps(JSON[key][item_id][attr])
elif len(components) == 1:
#/{attr} - search all items for `attr`
attr = components[0]
out = []
for k in JSON:
for d in JSON[k]:
if attr in d:
out.append(d[attr])
return json.dumps(out)
else:
return "unknown response"
return json.dumps(node)
if __name__ == "__main__":
urls = [
"/data/1/title",
"/title",
"/some_missing_attr",
"/favicon.ico",
"/",
]
for u in urls:
print u, "->", do_GET(u)
输出:
/data/1/title -> "\"Life's a Party\""
/title -> ["\"A Song for You\"", "\"Life's a Party\"", "\"Eternal Love\""]
/some_missing_attr -> []
/favicon.ico -> favicon response
/ -> error response
除非您真的想在任意 JSON 中进行任意嵌套查找,否则这应该会很好地工作。如果是这种情况,那么我认为您建议的 URL 不会起作用,您怎么知道“/titles”应该搜索所有元素而“/data”会查找一个元素?如果您真的想这样做,我会在 google 中搜索 "JSON query language",看看您可以重复使用哪些项目或从中获得灵感。