How to overload same named methods of different interfaces with type annotations in Python 3

Viewed 189

So I have Python 3 code like this:

from abc import ABC, abstractmethod                                                                                                                                                                                                                                                         
from datetime import datetime                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                            
class IfaceA(ABC):                                                                                                                                                                                                                                                                          
    @abstractmethod                                                                                                                                                                                                                                                                         
    def pass_data(self, data: str):                                                                                                                                                                                                                                                         
        pass                                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                            
class IfaceB(ABC):                                                                                                                                                                                                                                                                          
    @abstractmethod                                                                                                                                                                                                                                                                         
    def pass_data(self, data: datetime):                                                                                                                                                                                                                                                    
        pass                                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                            
class MyClass(IfaceA, IfaceB):                                                                                                                                                                                                                                                              
    def pass_data(self, data: str):                                                                                                                                                                                                                                                         
        print("str", data)                                                                                                                                                                                                                                                                  
                                                                                                                                                                                                                                                                                            
    def pass_data(self, data: datetime):                                                                                                                                                                                                                                                    
        print("datetime", data)                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                                            
def main():                                                                                                                                                                                                                                                                                 
    c = MyClass()                                                                                                                                                                                                                                                                           
    c.pass_data("Any string.")                                                                                                                                                                                                                                                              
    c.pass_data(datetime.now())                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                                            
if __name__ == "__main__":                                                                                                                                                                                                                                                                  
    main()

and it gives me output like this:

datetime Any string.
datetime 2020-07-13 02:00:34.676715

The IfaceA.pass_data method with str argument was not used.

Is there a way to make this work like in C++ ?

2 Answers

you can use multimethod

 from abc import ABC, abstractmethod                                                                                                                                                                                                                                                         
from datetime import datetime                                                                                                                                                                                                                                                               
from multimethod import multimethod
                                                                                                                                                                                                                                                                                          
class IfaceA(ABC):                                                                                                                                                                                                                                                                          
    @abstractmethod                                                                                                                                                                                                                                                                         
    def pass_data(self, data: str):                                                                                                                                                                                                                                                         
        pass                                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                            
class IfaceB(ABC):                                                                                                                                                                                                                                                                          
    @abstractmethod                                                                                                                                                                                                                                                                         
    def pass_data(self, data: datetime):                                                                                                                                                                                                                                                    
        pass                                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                            
class MyClass(IfaceA, IfaceB):
    @multimethod                                                                                                                                                                                                                                                           
    def pass_data(self, data: str):                                                                                                                                                                                                                                                         
        print("str", data)
    @multimethod                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
    def pass_data(self, data: datetime):                                                                                                                                                                                                                                                    
        print("datetime", data)                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                                            
def main():                                                                                                                                                                                                                                                                                 
    c = MyClass()                                                                                                                                                                                                                                                                           
    c.pass_data("Any string.")                                                                                                                                                                                                                                                              
    c.pass_data(datetime.now())                                                                                                                                                                                                                                                             
                                                                                                                                                                                                                                                                                            
if __name__ == "__main__":                                                                                                                                                                                                                                                                  
    main()

I don't think that's doable without some ugly non-pythonic hacks. The best you can do without hacks or 3rd party libs (with hacks) is this.

from datetime import datetime
from functools import singledispatchmethod


class MyClass:
    @singledispatchmethod
    def pass_data(self, val):
        raise NotImplementedError

    @pass_data.register
    def prints_str(self, data: str):
        print("str", data)


    @pass_data.register
    def prints_datetime(self, data: datetime):
        print("datetime", data)


def main():
    c = MyClass()
    c.pass_data("Any string.")
    c.pass_data(datetime.now())


if __name__ == "__main__":
    main()
Related