如何在Python中仅在返回类型提示中定义的情况下返回一个匿名NamedTuple

huangapple go评论60阅读模式
英文:

How to return a anonymous NamedTuple in python defined only in the return type hint

问题

I come from Typescript, new to Python. When I have 2 things to return from a function and I only use these 2 keys for that function return type and nowhere else in the code, I don't create a complete class but I instead use typescript convinient syntax:

fn(): {
    'return_key_1': number,
    'return_key_2': string,
} {
    // statements..
    return { 
    {
        'return_key_1': 5,
        'return_key_2': 'hello',
        'error_key': 9, // IDE shows an error here as I didn't declared this key
    }
}

which enables to create rapidly return data structure without the boilerplate of declaring an entire class, and I have all the IDE autocomplete and errors/warning associated with that data-structure.

Is there the same in Python? I saw there are NamedTuple, or new @dataclass classes from Python 3.7, but how do you make Python return a NamedTuple with defined keys without declaring the class elsewhere but in the return type?

I tried:

def fn(self) -> NamedTuple('MyTuple', fields=[('params', str), ('cursor_end', int)]):
    return {
        'params': 'hello',
        'cursor_end': 4,
    }

But PyCharm says "Expected type 'MyTuple', got 'dict[str, str | int]' instead"

英文:

I come from Typescript, new to Python. When I have 2 things to return from a function and I only use these 2 keys for that function return type and nowhere else in the code, I don't create a complete class but I instead use typescript convinient syntax:

fn(): {
    'return_key_1': number,
    'return_key_2': string,
} {
    // statements..
    return { 
    {
        'return_key_1': 5,
        'return_key_2': 'hello',
        'error_key': 9, // IDE shows an error here as I didn't declared this key
    }
}

which enables to create rapidly return data structure without the boilerplate of declaring a entire class, and I have all the IDE autocomplete and errors/warning associated to that data-structure.

Is there the same in Python ? I saw there are NamedTuple, or new @dataclass classes from Python 3.7, but how do you make Python return a NamedTuple with defined keys without declaring the class elsewhere but in the return type ?

I tried:

def fn(self) -> NamedTuple('MyTuple', fields = [('params', str), ('cursor_end', int)]):
    return {
        'params': 'hello',
        'cursor_end': 4,
    }

But PyCharm says "Expected type 'MyTuple', got 'dict[str, str | int]' instead"

答案1

得分: 2

由于您的样本函数返回一个字典,您应该使用typing.TypedDict来指定返回值的类型:

from typing import TypedDict

def f() -> TypedDict('', {
    'return_key_1': int,
    'return_key_2': str,
}):
    return {
        'return_key_1': 5,
        'return_key_2': 'hello',
        'error_key': 9, # PyCharm shows an error here
    }

请注意,正如@juanpa.arrivillaga在评论中指出的,虽然上述代码在PyCharm中看起来很干净且方便,但不幸的是,它并不是Python类型注释系统的官方部分。为了符合官方规范并满足严格遵循规范的工具,您需要预先定义TypedDict,而不是内联定义,如下例所示,几乎与上面的代码相同,只是提前命名了TypedDict

from typing import TypedDict

MyDict = TypedDict('MyDict', {
    'return_key_1': int,
    'return_key_2': str,
})

def f() -> MyDict:
    return {
        'return_key_1': 'a',
        'return_key_2': 'hello',
        'error_key': 9,
    }

在mypy中演示:https://mypy-play.net/?mypy=latest&python=3.11&gist=4fbb933f9f9441fced1931d7b32d4c7d

英文:

Since your sample function returns a dict, you should type the returning value with typing.TypedDict instead:

from typing import TypedDict

def f() -> TypedDict('', {
    'return_key_1': int,
    'return_key_2': str,
}):
    return {
        'return_key_1': 5,
        'return_key_2': 'hello',
        'error_key': 9, # PyCharm shows an error here
    }

Note, as @juanpa.arrivillaga points out in the comment, that while the above looks clean and conveniently works in PyCharm, it is unfortunately not officially part of the Python type annotation system. You would have to define the TypedDict in advance instead of inline in order to conform to the official specifications and satisfy tools that strictly adhere to the specs, like the example below, which is almost identical to the code above except in naming the TypedDict in advance:

from typing import TypedDict

MyDict = TypedDict('MyDict', {
    'return_key_1': int,
    'return_key_2': str,
})

def f() -> MyDict:
    return {
        'return_key_1': 'a',
        'return_key_2': 'hello',
        'error_key': 9,
    }

Demo in mypy: https://mypy-play.net/?mypy=latest&python=3.11&gist=4fbb933f9f9441fced1931d7b32d4c7d

huangapple
  • 本文由 发表于 2023年3月1日 10:12:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/75598980.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定