0

I'm trying to make a function that does different things when called on different argument types. Specifically, one of the functions should have the signature

def myFunc(string, string):

and the other should have the signature

def myFunc(list):

How can I do this, given that I'm not allowed to specify whether the arguments are strings or lists?

5
  • 2
    Short answer: there is basically no overloading of function parameters in the Python language. It's not a missing feature - it's a language concept. Commented Jun 29, 2012 at 21:48
  • IMO this is why a pattern matching library (like Racket's match) would be nice for Python Commented Jun 29, 2012 at 21:51
  • As the answers below should suggest, you have to start thinking about your problem a little differently--python has dynamic types, which is going to make its problem solving style different. It's possible to do some type checking at runtime, but without the dynamic dispatch on type of a statically type language like java, it's going to be an uphill battle. Commented Jun 29, 2012 at 21:51
  • Ben, I disagree, you can do this sort of thing easily in Racket using pattern matching, and Racket is dynamically typed. The only problem is that Python doesn't have macros, so implementing it would be annoying. Commented Jun 29, 2012 at 21:52
  • e.g. codepad.org/8Y8Nf0vY Commented Jun 29, 2012 at 22:18

6 Answers 6

2

Python does not support overloading, even by the argument count. You need to do:

def foo(string_or_list, string = None):
    if isinstance(string_or_list, list):
        ...
    else:
        ...

which is pretty silly, or just rethink your design to not have to overload.

Sign up to request clarification or add additional context in comments.

Comments

1

*args is probably the better way, but you could do something like:

def myFunc(arg1, arg2=None):
  if arg2 is not None: 
     #do this
  else:
     #do that

But that's probably a terrible way of doing it.

5 Comments

Don't check for equality of None, look for identity: if arg2 is not None.
What's the problem with an equality check for None?
@Russel: python.org/dev/peps/pep-0008/#programming-recommendations (see bullet 2). None is a singleton, it should always be compared using its identity (is/is not), not eqality.
I was hoping for a rationale beyond "PEP 8 says so". Is there any practical problem with using == here?
Best discussion I found was this: jaredgrubb.blogspot.com/2009/04/python-is-none-vs-none.html -- but in my value system, it actually makes me prefer ==.
1

There is a recipe at http://code.activestate.com/recipes/577065-type-checking-function-overloading-decorator/ which does what you want;

basically, you wrap each version of your function with @takes and @returns type declarations; when you call the function, it tries each version until it finds one that does not throw a type error.

Edit: here is a cut-down version; it's probably not a good thing to do, but if you gotta, here's how:

from collections import defaultdict

def overloaded_function(overloads):
    """
    Accepts a sequence of ((arg_types,), fn) pairs
    Creates a dispatcher function
    """
    dispatch_table = defaultdict(list)
    for arg_types,fn in overloads:
        dispatch_table[len(arg_types)].append([list(arg_types),fn])

    def dispatch(*args):
        for arg_types,fn in dispatch_table[len(args)]:
            if all(isinstance(arg, arg_type) for arg,arg_type in zip(args,arg_types)):
                return fn(*args)
        raise TypeError("could not find an overloaded function to match this argument list")

    return dispatch

and here's how it works:

def myfn_string_string(s1, s2):
    print("Got the strings {} and {}".format(s1, s2))

def myfn_list(lst):
    print("Got the list {}".format(lst))

myfn = overloaded_function([
    ((basestring, basestring), myfn_string_string),
    ((list,), myfn_list)
])

myfn("abcd", "efg")   # prints "Got the strings abcd and efg"
myfn(["abc", "def"])  # prints "Got the list ['abc', 'def']"
myfn(123)             # raises TypeError

Comments

1

Not a perfect solution, but if the second string argument will never legitimately be None, you could try:

def myFunc( firstArg, secondArg = None ):
    if secondArg is None:
        # only one arg provided, try treating firstArg as a list
    else:
        # two args provided, try treating them both as strings

Comments

0

Define it as taking variable arguments:

def myFunc(*args):

Then you can check the amount and type of the arguments via len and isinstance, and route the call to the appropriate case-specific function.

It may make for clearer code, however, if you used optional named arguments. It would be better still if you didn't use overloading at all, it's kinda not python's way.

Comments

0

You can't - for instance a class instance method can be inserted in run-time.

If you had multiple __init__ for a class for instance, you'd be better off with multiple @classmethod's such as from_strings or from_sequence

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.