Is a `Container` not supposed to contain types?

Hello,

I stumbled upon warning in PyCharm about an incompatible type for the argument of __contains__ in this example:

import collections.abc
import typing


class C(collections.abc.Container):
    def __init__(self) -> None:
        self._data = [int]

    def __contains__(self, val: typing.Type) -> bool:
        return val in set(self._data)


def test_():
    assert int in C()

I learned then that __contains__ is annotated like this in the typeshed project:

def __contains__(self, __x: object) -> bool: ...

Now I am wondering: is a container not supposed to contain types?

Bye,
jo

It can contain whatever you want, but you should be able to ask it if it contains arbitrary objects.

1 Like

This is is in line with that I expected.
Shouldn’t the annotation in the typeshed project then rather be Any?

No, Any and object both mean that the argument can be anything, but Any takes this to mean ‘so let me do anything with it’, essentially disabling type checking for the argument, whereas object instead says ‘so ensure that anything I do with it works with arbitrary objects’.

1 Like

All types inherit from object. Classes (also called types) are objects too:

>>> isinstance(int, object)
True

We’d have a better chance at understanding what is going on if you showed us the exact warning PyCharm gave, and which line it applies to.

The original post that I made in the PyCharm issue tracker is at https://youtrack.jetbrains.com/issue/PY-56228/False-positive-Type-of-contains-is-incompatible-with-Container.

EDIT: And now that I read this linked page, I also understand the issue. I was trying to make the type more specific in the class where I implemented __contains__ and this is what the warning is about:

It’s unsafe to override a method with a more specific argument type, as it violates the Liskov substitution principle. For return types, it’s unsafe to override a method with a more general return type.