Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python overload __init__

How do I overload __init__() in Python? I'm used to C/C++ where the compiler can see the difference in data type, but since there are no data types in Python, how can I make sure the third method gets called instead of the second when I give a string as parameter instead of an int?

class Handle:
    def __init__(self):
        self.pid = -1

    def __init__(self, pid):
        self.pid = pid

    def __init__(self, procname):
        print(procname)
        self.pid = -1 # find pid by name
like image 713
J. Daniel Avatar asked Aug 28 '26 22:08

J. Daniel


2 Answers

In C++ you can define multiple functions/methods with the same name and different signatures. In Python, everytime you define a new function with the same name of a previously defined function, you are replacing it.

To achieve what you want, you have to use optional arguments and/or explicit checks.

Here are a few possible solutions:

class Handle:
    def __init__(self, pid=-1):
        if isinstance(pid, str):
            self.procname = pid
            self.pid = -1
        else:
            self.procname = None
            self.pid = pid

class Handle:
    # Both pid and procname may be specified at the same time.
    def __init__(self, pid=-1, procname=None):
        self.procname = procname
        self.pid = pid

class Handle:
    # Either pid or procname, not both, may be specified.
    def __init__(self, pid=-1, procname=None):
        if pid >= 0 and procname is not None:
            raise ValueError('you can specify either pid or procname, not both')
        self.procname = procname
        self.pid = pid

class Handle:
    def __init__(self, pid=-1):
        self.pid = pid

    # A separate constructor, with a different name,
    # because "explicit is better than implicit" and
    # "sparse is better than dense" (cit. The Zen of
    # Python).
    # In my opinion, this is the most Pythonic solution.
    @classmethod
    def from_process_name(cls, procname):
        pid = get_pid(procname)
        return cls(pid)

By the way, I would not recommend using -1 for "not specified". I'd rather use None.

like image 75
Andrea Corbellini Avatar answered Aug 30 '26 11:08

Andrea Corbellini


Couldn't the PEP 443 : Single-dispatch generic functions be useful in your case ?

With something like (very basic example) :

from functools import singledispatch

class Handle:
    def __init__(self, arg=None):
        self.pid = init_from_arg(arg)

@singledispatch
def init_from_arg(arg):
    # If None or neither an integer nor a string, return None
    return None

# If the argument is an integer (ie the pid)
@init_from_arg.register(int)
def _(arg):
    return arg

# If the argument provided is a string (ie the procname)
@init_from_arg.register(str)
def _(arg):
    return get_pid_from_procname(arg)

Edit : Following the advice in comments, these functions could probably be made staticmethods, although I had trouble with them so I reverted to the code of my original answer (see edit history if needed)

like image 37
mgc Avatar answered Aug 30 '26 12:08

mgc