Cruncher
Cruncher

Reputation: 7796

Type hinting values that are multiple types?

My question is different than the title implies (I don't know how to summarize the question so I'm having a hard time googling).

I do not want a Union type. Union[A, B] says that the type can be either of type A, or of type B.

I need to the opposite. I want it to mean that it is both type A and B, which is possible in python because of mixins.

That is, I need to type hint a function such that I know the arguments passed will be of a class that has both A and B as parents, as my function uses methods from both mixins. A Union type hint allows passing something that has A without B which should not be allowed.

Example

from typing import Union

class A(object):
    def a(self):
        return True

class B(object):
    def b(self):
        return True

class C(A, B):
    pass

def foo(d: Union[A,B]) -> bool: #need something other than Union! 
    print(d.a() and d.b())

I need d to be an A and a B. But currently it allows me to send things that are A without being B, and errors when it tries to call the non-existent function

>>> foo(A())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in foo
AttributeError: 'A' object has no attribute 'b'
>>> foo(B())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in foo
AttributeError: 'B' object has no attribute 'a'
>>> foo(C())
True

Further I'd like to note, that the type can't just be d: C. This is because there are many classes that have A and B, and it would be a ridiculously long Union that would need to be maintained.

Upvotes: 15

Views: 3943

Answers (1)

Denis Sukhoverkhov
Denis Sukhoverkhov

Reputation: 90

You can use next OOP approach.

  1. Create interface - it's abstract class in python, which can show methods, which implements concrete classes. Example:

    from abc import ABC, abstractmethod
    
    class MyAB(ABC):
        @abstractmethod
        def a(self):
            pass
    
        @abstractmethod
        def b(self):
            pass
    
    
    class A(object):
        def a(self):
            return True
    
    
    class B(object):
        def b(self):
            return True
    
    
    class ConcreteClass(MyAB, A, B):
        pass
    
    
    def foo(d: MyAB):
        print(d.a() and d.b())
    
    
    c = ConcreteClass()
    
    foo(c)
    
  1. You say - parameter d in function foo can be able using two methods a and b. Thats all that you need.

Upvotes: 3

Related Questions