Vincent
Vincent

Reputation: 13415

A dictionary with a given key type cannot be assigned as a dictionary of objects

It looks like a dictionary of SomeKeyType cannot be assigned as a dictionary of objects, even though all types are subtypes of object:

x: dict[str, str] = {"a": "b"}
y: dict[object, str] = x
Incompatible types in assignment (expression has type "Dict[str, str]", variable has type "Dict[object, str]")

Copying doesn't help either:

x: dict[str, str] = {"a": "b"}
y: dict[object, str] = dict(x)
Argument 1 to "dict" has incompatible type "Dict[str, str]"; expected "SupportsKeysAndGetItem[object, str]"

A similar error occurs when updating a dictionary of objects with a dictionary of another type:

x: dict[object, str] = {"a": "a"}
y: dict[str, str] = {"b": "b"}

x.update(y)
x = {**x, **y}
x |= y
Argument 1 to "update" of "dict" has incompatible type "Dict[str, str]"; expected "Mapping[object, str]"
Argument 1 to "update" of "dict" has incompatible type "Dict[str, str]"; expected "Mapping[object, str]"
Argument 1 to "__ior__" of "dict" has incompatible type "Dict[str, str]"; expected "Mapping[object, str]"

Note that a naive implementation of dict.update does not generate any typing issue:

for k, v in y.items():
    x[k] = v

Is that on purpose or is it an issue I should report on the mypy tracker?

Upvotes: 1

Views: 2547

Answers (1)

joel
joel

Reputation: 7867

While a str is an object, it's not generally true that an F[str] is an F[object] for some type constructor F. For example, a dict[str, ...] is apparently not a dict[object, ...]. This is likely because dict[K, V] is invariant in its key type K, whereas you'd need it to be covariant. Types are often invariant in a type parameter because the type appears in both method argument and return type positions, like dict.__getitem__(key: K) -> V and dict.keys() -> KeysView[K].

You can fix your code by typing x as dict[object, str]. I guess this works because mypy then infers the "a" as an object, as opposed to inferring the dict[str, str] as a dict[object, str]. Whether that's the best solution for you depends on your context.

See this section of the mypy docs for more info on in-/co-/contravariance.

This discussion looks relevant though I only skimmed it.

Upvotes: 2

Related Questions