如何在 Python 中键入提示嵌套对象?

Tan*_*ing 7 python type-hinting python-3.x mypy zeep

我目前正在与 WSDL 进行集成,因此决定使用 Zeep 库与 Python 一起使用。

我正在尝试使用 对响应进行建模mypy,以便它可以与 VSCode 的 Intellisense 配合使用,并且在我进行粗心的分配或修改时也会给我一些提示。但是,当 WSDL 响应位于嵌套对象中时,我遇到了障碍,而且我无法找到对其进行类型提示的方法。

来自 WSDL 的示例响应:

{
    'result': {
        'code': '1',
        'description': 'Success',
        'errorUUID': None
    },
    'accounts': {
        'accounts': [
            {
                'accountId': 1,
                'accountName': 'Ming',
                'availableCredit': 1
            }
        ]
    }
}
Run Code Online (Sandbox Code Playgroud)

我正在使用以下代码段进行类型提示:

{
    'result': {
        'code': '1',
        'description': 'Success',
        'errorUUID': None
    },
    'accounts': {
        'accounts': [
            {
                'accountId': 1,
                'accountName': 'Ming',
                'availableCredit': 1
            }
        ]
    }
}
Run Code Online (Sandbox Code Playgroud)

对于尝试 1,原因很明显。但是在尝试了尝试 2 之后,我不知道如何继续了。我在这里缺少什么?

更新:按照@Avi Kaminetzky 的回答,我尝试了以下(操场):

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"
Run Code Online (Sandbox Code Playgroud)

但是我从 mypy 收到错误消息:

"getAccounts" has no attribute "result"
"getAccounts" has no attribute "accounts"
Run Code Online (Sandbox Code Playgroud)

Avr*_*zky 10

来自评论对话的更新

  1. 您将需要每个类都是 TypedDict 的子类。类似的东西class Foo(TypedDict)
  2. errorUUID是一个Optional[str]
  3. accounts是类型,Dict[str, List[AccountType]]因为它有一个内部(可能是多余的)键,也称为accounts.
  4. 您需要使用带有字符串化键的方括号来访问键 - 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
            }
        ]
    }
}
Run Code Online (Sandbox Code Playgroud)

看到这个 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/


Tan*_*ing 0

使用此答案作为参考,以下内容适用于我的情况(VSCode 中的智能感知,如果直接分配给变量则不起作用):

更新:使用另一个答案作为参考,我已经更新了我的代码以便能够以两种方式工作。(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
            }
        ]
    }
})

Run Code Online (Sandbox Code Playgroud)