如何对 Python 中的嵌套对象进行类型提示?
How can I type-hint a nested object in Python?
我目前正在与 WSDL 进行集成,因此决定 Python 使用 Zeep 库。
我正在尝试使用 mypy
对响应进行建模,以便它可以与 VSCode 的 Intellisense 一起使用,并在我进行粗心的分配或修改时给我一些提示.但是,当 WSDL 响应位于嵌套对象中时,我遇到了障碍,我想不出一种方法来对其进行类型提示。
来自 WSDL 的示例响应:
{
'result': {
'code': '1',
'description': 'Success',
'errorUUID': None
},
'accounts': {
'accounts': [
{
'accountId': 1,
'accountName': 'Ming',
'availableCredit': 1
}
]
}
}
我正在使用以下代码片段来输入提示:
class MethodResultType:
code: str
description: str
errorUUID: str
class AccountType:
accountId: int
accountName: str
availableCredit: float
class getAccounts:
result: MethodResultType
accounts: List[AccountType] # Attempt 1
accounts = TypedDict("accounts", {"accounts": List[AccountType]}) # Attempt 2
client = Client(os.getenv("API_URL"), wsse=user_name_token)
accountsResponse: getAccounts = client.service.getAccounts()
accounts = accountsResponse.accounts.accounts
# Attempt 1: "List[AccountType]" has no attribute "accounts"; maybe "count"?
# Attempt 2: "Type[accounts]" has no attribute "accounts"
对于尝试 1,原因很明显。但是在尝试了 Attempt 2 之后,我不知道如何进行了。我在这里错过了什么?
更新:
跟随@Avi Kaminetzky 的 , I tried with following (playground):
from typing import List, TypedDict, Optional, Dict
class MethodResultType(TypedDict):
code: str
description: str
errorUUID: Optional[str]
class AccountType(TypedDict):
accountId: int
accountName: str
availableCredit: float
class getAccounts(TypedDict):
result: MethodResultType
accounts: Dict[str, List[AccountType]]
result: getAccounts = {
'result': {
'code': '1',
'description': 'Success',
'errorUUID': None
},
'accounts': {
'accounts': [
{
'accountId': 1,
'accountName': 'Ming',
'availableCredit': 1
}
]
}
}
print(result.result)
print(result.accounts)
但我从 mypy 收到错误消息:
"getAccounts" has no attribute "result"
"getAccounts" has no attribute "accounts"
更新来自评论中的对话
- 您需要每个 class 都是 TypedDict 的子class。类似于
class Foo(TypedDict)
.
errorUUID
是一个 Optional[str]
.
accounts
是 Dict[str, List[AccountType]]
类型,因为它有一个内部(可能是多余的)键,也称为 accounts
.
- 您需要使用带有字符串化键的方括号来访问键 -
accountsResponse['accounts']['accounts']
.
这是一个建议的解决方案:
from typing import List, TypedDict, Optional, Dict
class MethodResultType(TypedDict):
code: str
description: str
errorUUID: Optional[str]
class AccountType(TypedDict):
accountId: int
accountName: str
availableCredit: float
class getAccounts(TypedDict):
result: MethodResultType
accounts: Dict[str, List[AccountType]]
result: getAccounts = {
'result': {
'code': '1',
'description': 'Success',
'errorUUID': None
},
'accounts': {
'accounts': [
{
'accountId': 1,
'accountName': 'Ming',
'availableCredit': 1
}
]
}
}
查看这个 MyPy 游乐场:
https://mypy-play.net/?mypy=latest&python=3.8&gist=dad62a9e2cecf4bad1088a2636690976
TypedDict 是 MyPy 的扩展,确保安装 MyPy(加上扩展)并导入 TypedDict:from typing_extensions import TypedDict
.
从 Python 3.8 开始,您可以直接从打字模块导入 TypedDict。
https://mypy.readthedocs.io/en/latest/more_types.html#typeddict
https://www.python.org/dev/peps/pep-0589/
使用此 answer 作为参考,以下适用于我的情况([=17= 中的智能感知],如果直接分配给变量则不起作用):
更新:使用另一个 answer 作为参考,我更新了我的代码以能够同时工作。 (Intellisense in VSCode,直接赋值入变量)
class MethodResultType:
code: str
description: str
errorUUID: str
class AccountType:
accountId: int
accountName: str
availableCredit: float
class accounts:
accounts: List[AccountType]
class getAccounts:
def __init__(self):
self.accounts = accounts()
result: MethodResultType
@property
def accounts(self):
return self.accounts
client = Client(os.getenv("API_URL"), wsse=user_name_token)
# Getting real response from WSDL
accountsResponse: getAccounts = client.service.getAccounts()
# For testing using sample response
sampleResponse: getAccounts = getAccounts({
'result': {
'code': '1',
'description': 'Success',
'errorUUID': None
},
'accounts': {
'accounts': [
{
'accountId': 1,
'accountName': 'Ming',
'availableCredit': 1
}
]
}
})
我目前正在与 WSDL 进行集成,因此决定 Python 使用 Zeep 库。
我正在尝试使用 mypy
对响应进行建模,以便它可以与 VSCode 的 Intellisense 一起使用,并在我进行粗心的分配或修改时给我一些提示.但是,当 WSDL 响应位于嵌套对象中时,我遇到了障碍,我想不出一种方法来对其进行类型提示。
来自 WSDL 的示例响应:
{
'result': {
'code': '1',
'description': 'Success',
'errorUUID': None
},
'accounts': {
'accounts': [
{
'accountId': 1,
'accountName': 'Ming',
'availableCredit': 1
}
]
}
}
我正在使用以下代码片段来输入提示:
class MethodResultType:
code: str
description: str
errorUUID: str
class AccountType:
accountId: int
accountName: str
availableCredit: float
class getAccounts:
result: MethodResultType
accounts: List[AccountType] # Attempt 1
accounts = TypedDict("accounts", {"accounts": List[AccountType]}) # Attempt 2
client = Client(os.getenv("API_URL"), wsse=user_name_token)
accountsResponse: getAccounts = client.service.getAccounts()
accounts = accountsResponse.accounts.accounts
# Attempt 1: "List[AccountType]" has no attribute "accounts"; maybe "count"?
# Attempt 2: "Type[accounts]" has no attribute "accounts"
对于尝试 1,原因很明显。但是在尝试了 Attempt 2 之后,我不知道如何进行了。我在这里错过了什么?
更新:
跟随@Avi Kaminetzky 的
from typing import List, TypedDict, Optional, Dict
class MethodResultType(TypedDict):
code: str
description: str
errorUUID: Optional[str]
class AccountType(TypedDict):
accountId: int
accountName: str
availableCredit: float
class getAccounts(TypedDict):
result: MethodResultType
accounts: Dict[str, List[AccountType]]
result: getAccounts = {
'result': {
'code': '1',
'description': 'Success',
'errorUUID': None
},
'accounts': {
'accounts': [
{
'accountId': 1,
'accountName': 'Ming',
'availableCredit': 1
}
]
}
}
print(result.result)
print(result.accounts)
但我从 mypy 收到错误消息:
"getAccounts" has no attribute "result"
"getAccounts" has no attribute "accounts"
更新来自评论中的对话
- 您需要每个 class 都是 TypedDict 的子class。类似于
class Foo(TypedDict)
. errorUUID
是一个Optional[str]
.accounts
是Dict[str, List[AccountType]]
类型,因为它有一个内部(可能是多余的)键,也称为accounts
.- 您需要使用带有字符串化键的方括号来访问键 -
accountsResponse['accounts']['accounts']
.
这是一个建议的解决方案:
from typing import List, TypedDict, Optional, Dict
class MethodResultType(TypedDict):
code: str
description: str
errorUUID: Optional[str]
class AccountType(TypedDict):
accountId: int
accountName: str
availableCredit: float
class getAccounts(TypedDict):
result: MethodResultType
accounts: Dict[str, List[AccountType]]
result: getAccounts = {
'result': {
'code': '1',
'description': 'Success',
'errorUUID': None
},
'accounts': {
'accounts': [
{
'accountId': 1,
'accountName': 'Ming',
'availableCredit': 1
}
]
}
}
查看这个 MyPy 游乐场: https://mypy-play.net/?mypy=latest&python=3.8&gist=dad62a9e2cecf4bad1088a2636690976
TypedDict 是 MyPy 的扩展,确保安装 MyPy(加上扩展)并导入 TypedDict:from typing_extensions import TypedDict
.
从 Python 3.8 开始,您可以直接从打字模块导入 TypedDict。
https://mypy.readthedocs.io/en/latest/more_types.html#typeddict https://www.python.org/dev/peps/pep-0589/
使用此 answer 作为参考,以下适用于我的情况([=17= 中的智能感知],如果直接分配给变量则不起作用):
更新:使用另一个 answer 作为参考,我更新了我的代码以能够同时工作。 (Intellisense in VSCode,直接赋值入变量)
class MethodResultType:
code: str
description: str
errorUUID: str
class AccountType:
accountId: int
accountName: str
availableCredit: float
class accounts:
accounts: List[AccountType]
class getAccounts:
def __init__(self):
self.accounts = accounts()
result: MethodResultType
@property
def accounts(self):
return self.accounts
client = Client(os.getenv("API_URL"), wsse=user_name_token)
# Getting real response from WSDL
accountsResponse: getAccounts = client.service.getAccounts()
# For testing using sample response
sampleResponse: getAccounts = getAccounts({
'result': {
'code': '1',
'description': 'Success',
'errorUUID': None
},
'accounts': {
'accounts': [
{
'accountId': 1,
'accountName': 'Ming',
'availableCredit': 1
}
]
}
})