Search code examples
pythonpython-3.xpython-typingpython-3.9

What's "and" operator for type hints in python?


I'm going to make a "type alias" for a combination of several types. I can create a new class for most types, but this makes the code too long and type checkers can't show it. I'm looking for a better alternative. we can use Union for A | B but I need A & B.

Example:

from typing import TypeVar

T = TypeVar('T')


class Identify:
    id: int


def test_type_hints(obj: T) -> T & Identify:  # This Line
    obj.id = id(obj)

If I can do it, How? else Why?


Solution

  • The code you show doesn't actually turn obj into an instance of Identify, so the type hint you're asking to add would be misleading. Calling isinstance(obj, Identify) would be false, at runtime, and no type checking declarations would accept the object as an instance of the class.

    If you want the Identify type not to be a real type that expects you to subclass and make instances of it, but just a signifier for "an object with an id attribute", then you should make it a typing.Protocol. A protocol does just what you want, it lets you describe the features an object must have, and any such object, of any type, will be accepted wherever the an object obeying the protocol is expected.

    from typing import Protocol
    
    class Identify(typing.Protocol):
        id: int
    
    class MyObj:
        pass
        
    o = MyObj()
    print(isinstance(o, Identify)) # prints False
    
    o.id = 2
    print(isinstance(o, Identify)) # prints True now
    

    This doesn't exactly solve your issue though, as there's not really a mechanism in Python type hinting to dynamically declare an intersection of types (it's been a requested feature for a long time). A crude approach that might work for some situations would be to discard the old type information and just preserve the new knowledge of the protocol, but this might not be good enough for your use case:

    def test_type_hints(obj: typing.Any) -> Identify:
        obj.id = id(obj)
        return obj