简体   繁体   中英

Make a Union of strings to be used as possible dictionary keys

I have some Python 3.7 code and I am trying to add types to it. One of the types I want to add is actually an Union of several possible strings:

from typing import Union, Optional, Dict

PossibleKey = Union["fruits", "cars", "vegetables"]
PossibleType = Dict[PossibleKey, str]

def some_function(target: Optional[PossibleType] = None):
  if target:
    all_fruits = target["fruits"]
    print(f"I have {all_fruits}")

The problem here is that Pyright complains about PossibleKey . It says:

"fruits is not defined"

I would like to get Pyright/Pylance to work.

I have checked the from enum import Enum module from another SO answer, but if I try that I end up with more issues since I am actually dealing with a Dict[str, Any] and not an Enum .

What is the proper Pythonic way of representing my type?

"fruits" is not a type (hint), but Literal["fruits"] is.

from typing import Union, Literal

PossibleKey = Union[Literal["fruits"], Literal["cars"], Literal["vegetables"]]

or the much shorter version,

PossibleKey = Literal["fruits", "cars", "vegetables"]

Or, as you mentioned, define an Enum populated by the three values.

from enum import Enum


class Key(Enum):
    Fruits = "fruits"
    Cars = "cars"
    Vegetables = "vegetables"


def some_function(target: Optional[PossibleType] = None):
    if target:
        all_fruits = target[Key.Fruits]
        print(f"I have {all_fruits}")

(However, just because target is not None doesn't necessarily mean it actually has "fruits" as a key, only that doesn't have a key other than Key.Fruits , Key.Cars , or Key.Vegetables .)

Pyright error disappears if you define PossibleKey as Enum as below. This requires only one line change to the original code. If there is some issue with using Enum, please elaborate on that.

from typing import Union, Optional, Dict
from enum import Enum

PossibleKey = Enum("PossibleKey", ["fruits", "cars", "vegetables"])
PossibleType = Dict[PossibleKey, str]

def some_function(target: Optional[PossibleType] = None):
  if target:
    all_fruits = target["fruits"]
    print(f"I have {all_fruits}")

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM