如何使用一次性泛型创建类型别名?

问题描述 投票:0回答:1

我正在创建一个类型别名,它可以采用别名中实际未使用的泛型。原因是自记录代码,我知道没有类型检查器能够实际检查这一点。这就是我的意思:

from typing import TypeVar, Dict, Any

from dataclasses import dataclass
from dataclasses_json import dataclass_json, DataClassJsonMixin


JSON = Dict[str, Any]  # Good enough json type for this demo
T = TypeVar("T", bound=DataClassJsonMixin)
JSONOf = JSON[T]  # <-- mypy Problem: JSON takes no generic arguments

@dataclass_json   # this just provides to_json/from_json to dataclasses, not important for question
@dataclass
class Person:
    name: str
    age: int

def add_person_to_db(person: JSONOf[Person]):
    # just from reading the signature the user now knows what the input is
    # If I just put JSON as a type, it is unclear
    ...

问题是JSON类型别名没有使用泛型参数,所以无法接收。我需要在别名定义中使用它,而不需要实际使用它做一些事情。我尝试使用 PEP-593 Annotated 类型执行此操作,但它也不起作用(我可以像下面一样定义它,但它仍然不需要通用参数):

from typing import Annotated

JSONOf = Annotated[JSON, T]

我需要做类似的事情(这不存在):

from typing import ThrowAwayGeneric

JSONOf = ThrowAwayGeneric[JSON, T]

是否可以获得类似于类型检查的东西?再说一遍:我实际上对 json 数据的类型检查并不感兴趣,我只是想提供函数的可读签名。在实际类型检查时使用

Dict[str, Any]
是否完全没问题。

这种强力方法当然是为每种类型定义一个别名,但这会变得乏味,因为有很多这样的类型。

JSONOfPerson = JSON
python mypy python-typing type-alias
1个回答
1
投票

我想出了一些解决方案:

  • JSONOf
    与另一种采用泛型的类型结合起来,以永远不会匹配任何内容的方式制作该类型,例如具有可变键的
    JSON
    
    
  • Dict
相同的方法,与自定义泛型类结合:
  • JSONOf = Union[JSON, Dict[List, T]] # List could be any mutable, including JSON itself
我们来测试一下:

class JSONFrom(Generic[T]): pass # Name was chosen to look nice on mypy errors JSONOf = Union[JSON, JSONFrom[T]]

from typing import Generic, TypeVar, Dict, Any, Union

class DataClassJsonMixin: ...
class Person(DataClassJsonMixin): ...
JSON = Dict[str, Any]  # Good enough json type for this demo
T = TypeVar("T", bound=DataClassJsonMixin)

# Solution 1: Union with impossible type that takes a Generic
# JSONOf = Union[JSON, Dict[JSON, T]]

# Solution 2: Union with custom generic class
class JSONFrom(Generic[T]):
    # just a crude failsafe to prohibit instantiation
    # could be improved with __new__, __init_subclasses__, etc
    def __init__(self):
        raise TypeError("Just dont!")

JSONOf = Union[JSON, JSONFrom[T]]

def add_person_to_db(person: JSONOf[Person]):
    print(person)
    try: reveal_type(person)
    except NameError: pass

add_person_to_db({'id': 1234, 'name': 'Someone'})  # Checks
add_person_to_db("Not a JSON")       # Check error by JSON
add_person_to_db(Person())           # Make sure it does not accept Person
try: someone: JSONFrom = JSONFrom()  # Make sure it does not accept JSONFrom
except TypeError as e: print(e)      # Nice try!
	
© www.soinside.com 2019 - 2024. All rights reserved.