Here is the problem:

我有一本字典,使用两种不同类型的键(city_keyvillage_key)记录两种不同类型的值(比如cityvillage).我想用泛型来注释这个字典,这样当字典收到city_key类型的键时,mypy/Pyright应该将返回值注释为city.同样,如果try 将city值赋给village_key,mypy/pyright应该会抛出一个错误.

另一种 Select 是维护两个不同的字典,一个用于城市,一个用于村庄,但我很好奇我是否可以只使用一个字典.

What I've tried so far

我研究了这个问题,但没有找到明确的例子/答案.有一个问题和我的here个一样,但没有得到回答.

Some pseudo code to show what I am aiming for in practice


# two types of aliased keys
# ... edited to use NewType as per juanpa.arrivillaga comment

CityKey = NewType("CityKey", str)
VillageKey = NewType("VillageKey", str)

# two types of values, city and village
class City:...
class Village:...

# key generator that returns city or village key based on type of input
def generate_key(settlement: City | Village) -> CityKey | VillageKey: ...

# declare some keys & values
london = City("London")
london_key = generate_key(london)
mousehole = Village("Mousehole")
mousehole_key = generate_key(village)

# instantiate the dictionary
data: [????] = {}

# assign city to city key, and village to village key
data[london_key] = london
data[mousehole_key] = mousehole

# trying to assign village to city key should raise a type check error
data[london_key] = mousehole

# type of value accessed by village key should be village
reveal_type(data[mousehole_key]) # Type[Village]

非常感谢.

附言

推荐答案

你可以使用typing.overload来实现这个目的,这可以帮助我们从Callable[[A1 | B1], A2 | B2]这样的类型转换为Callable[[A1], A2]Callable[[B1], B2],以及dict的子类.

from typing import overload

@overload
def generate_key(settlement: City) -> CityKey:
    # Just a stub
    ...


@overload
def generate_key(settlement: Village) -> VillageKey:
    # Just a stub
    ...


def generate_key(settlement):
    # Contains the actual implementation
    [...]


class CityOrVillageDict(dict):
    @overload
    def __setitem__(self, key: CityKey, value: City) -> None:
        # Just a stub
        ...

    @overload
    def __setitem__(self, key: VillageKey, value: Village) -> None:
        # Just a stub
        ...

    def __setitem__(self, key, value):
        # Overloaded functions need an implementation
        super().__setitem__(key, value)

    @overload
    def __getitem__(self, key: CityKey) -> City:
        # Just a stub
        ...

    @overload
    def __getitem__(self, key: VillageKey) -> Village:
        # Just a stub
        ...

    def __getitem__(self, key):
        # Overloaded functions need an implementation
        return super().__getitem__(key)

data = CityOrVillageDict()

Python相关问答推荐

当多个值具有相同模式时返回空

可变参数数量的重载类型(args或kwargs)

按列分区,按另一列排序

如何使用LangChain和AzureOpenAI在Python中解决AttribeHelp和BadPressMessage错误?

Telethon加入私有频道

用渐近模计算含符号的矩阵乘法

Python Pandas获取层次路径直到顶层管理

使用Python查找、替换和调整PDF中的图像'

ruamel.yaml dump:如何阻止map标量值被移动到一个新的缩进行?

提高算法效率的策略?

pandas:在操作pandora之后将pandora列转换为int

如何根据rame中的列值分别分组值

Python Mercury离线安装

如何获取包含`try`外部堆栈的`__traceback__`属性的异常

为什么按下按钮后屏幕的 colored颜色 保持不变?

如何删除剪裁圆的对角线的外部部分

跨两个数据帧收集非索引列上的公共组

为什么fizzbuzz在两个数字的条件出现在一个数字的条件之后时不起作用?

如何更改网络中某条边的位置(&Q;)?

以元组为索引的Numpy多维索引