将 dict 变成 TypedDict 的好方法?
Nice way to turn a dict into a TypedDict?
我想要一个很好的(mypy --strict
和 pythonic)方法来将无类型的 dict
(来自 json.loads()
)转换为 TypedDict
。我目前的做法是这样的:
class BackupData(TypedDict, total=False):
archive_name: str
archive_size: int
transfer_size: int
transfer_time: float
error: str
def to_backup_data(data: Mapping[str, Any]) -> BackupData:
result = BackupData()
if 'archive_name' in data:
result['archive_name'] = str(data['archive_name'])
if 'archive_size' in data:
result['archive_size'] = int(data['archive_size'])
if 'transfer_size' in data:
result['transfer_size'] = int(data['transfer_size'])
if 'transfer_time' in data:
result['transfer_time'] = int(data['transfer_time'])
if 'error' in data:
result['error'] = str(data['error'])
return result
即我有一个带有可选键的 TypedDict
并且想要一个 TypedDict
实例。
上面的代码是冗余的和非功能性的(就函数式编程而言),因为我必须写四次名称,输入两次并且 result
必须是可变的。
遗憾的是 TypedDict
不能有方法,否则我可以写 s.th。喜欢
backup_data = BackupData.from(json.loads({...}))
关于 TypeDict
我是否遗漏了什么?这可以用一种漂亮的、非冗余的方式编写吗?
当您使用 TypedDict 时,所有信息都存储在 __annotations__
字段中。
以你的例子为例:
BackupData.__annotations__
returns:
{'archive_name': <class 'str'>, 'archive_size': <class 'int'>, 'transfer_size': <class 'int'>, 'transfer_time': <class 'float'>, 'error': <class 'str'>}
现在我们可以使用该字典迭代数据并使用值进行类型转换:
def to_backup_data(data: Mapping[str, Any]) -> BackupData:
result = BackupData()
for key, key_type in BackupData.__annotations__.items():
if key not in data:
raise ValueError(f"Key: {key} is not available in data.")
result[key] = key_type(data[key])
return result
请注意,当数据不可用时我会抛出一个错误,这可以根据您的判断进行更改。
使用以下测试代码:
data = dict(
archive_name="my archive",
archive_size="50",
transfer_size="100",
transfer_time="2.3",
error=None,
)
for key, value in result.items():
print(f"Key: {key.ljust(15)}, type: {str(type(value)).ljust(15)}, value: {value!r}")
结果将是:
Key: archive_name , type: <class 'str'> , value: 'my archive'
Key: archive_size , type: <class 'int'> , value: 50
Key: transfer_size , type: <class 'int'> , value: 100
Key: transfer_time , type: <class 'float'>, value: 2.3
Key: error , type: <class 'str'> , value: 'None'
我想要一个很好的(mypy --strict
和 pythonic)方法来将无类型的 dict
(来自 json.loads()
)转换为 TypedDict
。我目前的做法是这样的:
class BackupData(TypedDict, total=False):
archive_name: str
archive_size: int
transfer_size: int
transfer_time: float
error: str
def to_backup_data(data: Mapping[str, Any]) -> BackupData:
result = BackupData()
if 'archive_name' in data:
result['archive_name'] = str(data['archive_name'])
if 'archive_size' in data:
result['archive_size'] = int(data['archive_size'])
if 'transfer_size' in data:
result['transfer_size'] = int(data['transfer_size'])
if 'transfer_time' in data:
result['transfer_time'] = int(data['transfer_time'])
if 'error' in data:
result['error'] = str(data['error'])
return result
即我有一个带有可选键的 TypedDict
并且想要一个 TypedDict
实例。
上面的代码是冗余的和非功能性的(就函数式编程而言),因为我必须写四次名称,输入两次并且 result
必须是可变的。
遗憾的是 TypedDict
不能有方法,否则我可以写 s.th。喜欢
backup_data = BackupData.from(json.loads({...}))
关于 TypeDict
我是否遗漏了什么?这可以用一种漂亮的、非冗余的方式编写吗?
当您使用 TypedDict 时,所有信息都存储在 __annotations__
字段中。
以你的例子为例:
BackupData.__annotations__
returns:
{'archive_name': <class 'str'>, 'archive_size': <class 'int'>, 'transfer_size': <class 'int'>, 'transfer_time': <class 'float'>, 'error': <class 'str'>}
现在我们可以使用该字典迭代数据并使用值进行类型转换:
def to_backup_data(data: Mapping[str, Any]) -> BackupData:
result = BackupData()
for key, key_type in BackupData.__annotations__.items():
if key not in data:
raise ValueError(f"Key: {key} is not available in data.")
result[key] = key_type(data[key])
return result
请注意,当数据不可用时我会抛出一个错误,这可以根据您的判断进行更改。
使用以下测试代码:
data = dict(
archive_name="my archive",
archive_size="50",
transfer_size="100",
transfer_time="2.3",
error=None,
)
for key, value in result.items():
print(f"Key: {key.ljust(15)}, type: {str(type(value)).ljust(15)}, value: {value!r}")
结果将是:
Key: archive_name , type: <class 'str'> , value: 'my archive'
Key: archive_size , type: <class 'int'> , value: 50
Key: transfer_size , type: <class 'int'> , value: 100
Key: transfer_time , type: <class 'float'>, value: 2.3
Key: error , type: <class 'str'> , value: 'None'