Python 在列表理解中引发错误(或更好的选择)
Python Raising Errors within List Comprehension (or a better alternative)
我有一个从 json 字符串中读取的嵌套结构,看起来类似于以下内容...
[
{
"id": 1,
"type": "test",
"sub_types": [
{
"id": "a",
"type": "sub-test",
"name": "test1"
},
{
"id": "b",
"name": "test2",
"key_value_pairs": [
{
"key": 0,
"value": "Zero"
},
{
"key": 1,
"value": "One"
}
]
}
]
}
]
我需要提取和转换数据,准备插入到数据库中...
[
(1, "b", 0, "Zero"),
(1, "b", 1, "One")
]
我正在做以下事情...
data_list = [
(
type['id'],
sub_type['id'],
key_value_pair['key'],
key_value_pair['value']
)
for type in my_parsed_json_array
if 'sub_types' in type
for sub_type in type['sub_types']
if 'key_value_pairs' in sub_type
for key_value_pair in sub_type['key_value_pairs']
]
到目前为止,还不错。
但是,我接下来需要做的是强制执行一些限制。例如...
if type['type'] == 'test': raise ValueError('[test] types can not contain key_value_pairs.')
但我无法理解。而且我不想求助于循环。到目前为止我最好的想法是...
def make_row(type, sub_type, key_value_pair):
if type['type'] == 'test': raise ValueError('sub-types of a [test] type can not contain key_value_pairs.')
return (
type['id'],
sub_type['id'],
key_value_pair['key'],
key_value_pair['value']
)
data_list = [
make_row(
type,
sub_type,
key_value_pair
)
for type in my_parsed_json_array
if 'sub_types' in type
for sub_type in type['sub_types']
if 'key_value_pairs' in sub_type
for key_value_pair in sub_type['key_value_pairs']
]
这行得通,但它会对每个 key_value_pair 进行检查,这感觉是多余的。 (每组键值对可能有几千对,只需要检查一次就可以了。)
此外,还有其他类似的规则适用于层次结构的不同级别。比如"test"类型只能包含"sub_test"sub_types.
除了以上选项还有哪些选项?
- 更优雅?
- 更具可扩展性?
- 性能更高?
- 更多"Pythonic"?
您应该阅读有关如何验证 json
数据并指定显式架构约束的信息
JSON Schema
该库允许您设置所需的键、指定默认值、添加类型验证等。
这个库在这里有它的 python 实现:
jsonschema package
示例:
from jsonschema import Draft6Validator
schema = {
"$schema": "https://json-schema.org/schema#",
"type": "object",
"properties": {
"name": {"type": "string"},
"email": {"type": "string"},
},
"required": ["email"]
}
Draft6Validator.check_schema(schema)
我只想使用普通循环,但如果将语句放入函数中,您可以将其添加到第一个条件检查中:
def type_check(type):
if type['type'] == 'test':
raise ValueError('sub-types of a [test] type can not contain key_value_pairs.')
return True
data_list = [
(
type['id'],
sub_type['id'],
key_value_pair['key'],
key_value_pair['value']
)
for type in my_parsed_json_array
if 'sub_types' in type
for sub_type in type['sub_types']
if 'key_value_pairs' in sub_type and type_check(type)
for key_value_pair in sub_type['key_value_pairs']
]
您可以按照
的方式尝试架构
def validate_top(obj):
if obj['type'] in BAD_TYPES:
raise ValueError("oof")
elif obj['type'] not in IRRELEVANT_TYPES: # actually need to include this
yield obj
def validate_middle(obj):
# similarly for the next nested level of data
# and so on
[
make_row(r)
for t in validate_top(my_json)
for m in validate_middle(t)
# etc...
for r in validate_last(whatever)
]
我这里的一般模式是使用生成器(函数,而不是表达式)处理数据,然后理解收集它。
在更简单的情况下,不值得分离出多个级别的处理(或者它们自然不存在),您仍然可以编写一个生成器并只执行类似 list(generator(source))
的操作。在我看来,这仍然比使用普通函数并手动构建列表更清晰 - 它仍然将 'processing' 与 'collecting' 问题分开。
我有一个从 json 字符串中读取的嵌套结构,看起来类似于以下内容...
[
{
"id": 1,
"type": "test",
"sub_types": [
{
"id": "a",
"type": "sub-test",
"name": "test1"
},
{
"id": "b",
"name": "test2",
"key_value_pairs": [
{
"key": 0,
"value": "Zero"
},
{
"key": 1,
"value": "One"
}
]
}
]
}
]
我需要提取和转换数据,准备插入到数据库中...
[
(1, "b", 0, "Zero"),
(1, "b", 1, "One")
]
我正在做以下事情...
data_list = [
(
type['id'],
sub_type['id'],
key_value_pair['key'],
key_value_pair['value']
)
for type in my_parsed_json_array
if 'sub_types' in type
for sub_type in type['sub_types']
if 'key_value_pairs' in sub_type
for key_value_pair in sub_type['key_value_pairs']
]
到目前为止,还不错。
但是,我接下来需要做的是强制执行一些限制。例如...
if type['type'] == 'test': raise ValueError('[test] types can not contain key_value_pairs.')
但我无法理解。而且我不想求助于循环。到目前为止我最好的想法是...
def make_row(type, sub_type, key_value_pair):
if type['type'] == 'test': raise ValueError('sub-types of a [test] type can not contain key_value_pairs.')
return (
type['id'],
sub_type['id'],
key_value_pair['key'],
key_value_pair['value']
)
data_list = [
make_row(
type,
sub_type,
key_value_pair
)
for type in my_parsed_json_array
if 'sub_types' in type
for sub_type in type['sub_types']
if 'key_value_pairs' in sub_type
for key_value_pair in sub_type['key_value_pairs']
]
这行得通,但它会对每个 key_value_pair 进行检查,这感觉是多余的。 (每组键值对可能有几千对,只需要检查一次就可以了。)
此外,还有其他类似的规则适用于层次结构的不同级别。比如"test"类型只能包含"sub_test"sub_types.
除了以上选项还有哪些选项?
- 更优雅?
- 更具可扩展性?
- 性能更高?
- 更多"Pythonic"?
您应该阅读有关如何验证 json
数据并指定显式架构约束的信息
JSON Schema
该库允许您设置所需的键、指定默认值、添加类型验证等。
这个库在这里有它的 python 实现: jsonschema package
示例:
from jsonschema import Draft6Validator
schema = {
"$schema": "https://json-schema.org/schema#",
"type": "object",
"properties": {
"name": {"type": "string"},
"email": {"type": "string"},
},
"required": ["email"]
}
Draft6Validator.check_schema(schema)
我只想使用普通循环,但如果将语句放入函数中,您可以将其添加到第一个条件检查中:
def type_check(type):
if type['type'] == 'test':
raise ValueError('sub-types of a [test] type can not contain key_value_pairs.')
return True
data_list = [
(
type['id'],
sub_type['id'],
key_value_pair['key'],
key_value_pair['value']
)
for type in my_parsed_json_array
if 'sub_types' in type
for sub_type in type['sub_types']
if 'key_value_pairs' in sub_type and type_check(type)
for key_value_pair in sub_type['key_value_pairs']
]
您可以按照
的方式尝试架构def validate_top(obj):
if obj['type'] in BAD_TYPES:
raise ValueError("oof")
elif obj['type'] not in IRRELEVANT_TYPES: # actually need to include this
yield obj
def validate_middle(obj):
# similarly for the next nested level of data
# and so on
[
make_row(r)
for t in validate_top(my_json)
for m in validate_middle(t)
# etc...
for r in validate_last(whatever)
]
我这里的一般模式是使用生成器(函数,而不是表达式)处理数据,然后理解收集它。
在更简单的情况下,不值得分离出多个级别的处理(或者它们自然不存在),您仍然可以编写一个生成器并只执行类似 list(generator(source))
的操作。在我看来,这仍然比使用普通函数并手动构建列表更清晰 - 它仍然将 'processing' 与 'collecting' 问题分开。