Search code examples
pythonpython-3.8

How to use positional arguments in `__init__` while using `singledispatchmethod`


I am trying to different ways to instantiate Service class. That's means some times I have to pass (a: str, b: str) and sometimes (d: dict). To do so, I am using singledispatchmethod from functools to have two ways to define __init__ method. See the code below:

from functools import singledispatchmethod


class Service:
    
    @singledispatchmethod
    def __init__(self, d: dict):
        self.a = d.get('a')
        self.b = d.get('b')
        
    @__init__.register
    def _(self, a: str, b: str):
        d = {"a": a, "b": b}
        self.__init__(d)

when I instantiate using non positional arguments it works as expected. But with positional argument:

s = Service(d={"a":1, "b": 2})

it raises an error tuple index out of range, this is the return traceback:

Traceback (most recent call last):
  File "/*/*/*/scratch_3.py", line 16, in <module>
    s = Service(d={"a":1, "b": 2})
  File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/functools.py", line 911, in _method
    method = self.dispatcher.dispatch(args[0].__class__)
IndexError: tuple index out of range

What change should be done here, to be able to use positional argument?


Solution

  • If you don't need to use singledispatchmethod, then here is one example you can use with isinstance.

    class Service:
        
        def __init__(self, d, b=None):
    
            if isinstance(d, dict):
                
                self.a = d.get('a')
                self.b = d.get('b')
    
            elif isinstance(d, str) and isinstance(b, str):
    
                self.a = d
                self.b = b