Reputation: 2747
I am trying to implement method overloading in Python:
class A:
def stackoverflow(self):
print ('first method')
def stackoverflow(self, i):
print ('second method', i)
ob=A()
ob.stackoverflow(2)
but the output is second method 2
; similarly:
class A:
def stackoverflow(self):
print ('first method')
def stackoverflow(self, i):
print ('second method', i)
ob=A()
ob.stackoverflow()
gives
Traceback (most recent call last):
File "my.py", line 9, in <module>
ob.stackoverflow()
TypeError: stackoverflow() takes exactly 2 arguments (1 given)
How do I make this work?
Upvotes: 253
Views: 324548
Reputation: 3294
Now (3.11), You can do overload in python using typing. https://docs.python.org/3/library/typing.html#typing.overload
Following directly copied from the given url.
@typing.overload
Decorator for creating overloaded functions and methods.
The @overload decorator allows describing functions and methods that support multiple different combinations of argument types. A series of @overload-decorated definitions must be followed by exactly one non-@overload-decorated definition (for the same function/method).
@overload-decorated definitions are for the benefit of the type checker only, since they will be overwritten by the non-@overload-decorated definition. The non-@overload-decorated definition, meanwhile, will be used at runtime but should be ignored by a type checker. At runtime, calling an @overload-decorated function directly will raise NotImplementedError.
An example of overload that gives a more precise type than can be expressed using a union or a type variable:
@overload
def process(response: None) -> None:
...
@overload
def process(response: int) -> tuple[int, str]:
...
@overload
def process(response: bytes) -> str:
...
def process(response):
... # actual implementation goes here
Upvotes: 0
Reputation: 176780
It's method overloading, not method overriding. And in Python, you historically do it all in one function:
class A:
def stackoverflow(self, i='some_default_value'):
print('only method')
ob=A()
ob.stackoverflow(2)
ob.stackoverflow()
See the Default Argument Values section of the Python tutorial. See "Least Astonishment" and the Mutable Default Argument for a common mistake to avoid.
See PEP 443 for information about the single dispatch generic functions added in Python 3.4:
>>> from functools import singledispatch
>>> @singledispatch
... def fun(arg, verbose=False):
... if verbose:
... print("Let me just say,", end=" ")
... print(arg)
>>> @fun.register(int)
... def _(arg, verbose=False):
... if verbose:
... print("Strength in numbers, eh?", end=" ")
... print(arg)
...
>>> @fun.register(list)
... def _(arg, verbose=False):
... if verbose:
... print("Enumerate this:")
... for i, elem in enumerate(arg):
... print(i, elem)
Upvotes: 188
Reputation: 1208
You can also use pythonlangutil:
from pythonlangutil.overload import Overload, signature
class A:
@Overload
@signature()
def stackoverflow(self):
print('first method')
@stackoverflow.overload
@signature("int")
def stackoverflow(self, i):
print('second method', i)
Upvotes: 116
Reputation: 2075
python 3.5 added the typing module. This included an overload decorator.
This decorator's intended purpose it to help type checkers. Functionally its just duck typing.
from typing import Optional, overload
@overload
def foo(index: int) -> str:
...
@overload
def foo(name: str) -> str:
...
@overload
def foo(name: str, index: int) -> str:
...
def foo(name: Optional[str] = None, index: Optional[int] = None) -> str:
return f"name: {name}, index: {index}"
foo(1)
foo("bar", 1)
foo("bar", None)
This leads to the following type information in vs code:
And while this can help, note that this adds lots of "weird" new syntax. Its purpose - purely type hints - is not immediately obvious.
Going with Union of types usually is a better option.
Upvotes: 10
Reputation: 1253
There are some libraries that make this easy:
functools
- if you only need the first argument use @singledispatch
plum-dispatch
- feature rich method/function overloading.
multipledispatch
- alternative to plum
less features but lightweight.
Upvotes: 3
Reputation: 4485
While agf was right with the answer in the past, pre-3.4, now with PEP-3124 we got our syntactic sugar.
See typing documentation for details on the @overload
decorator, but note that this is really just syntactic sugar and IMHO this is all people have been arguing about ever since.
Personally, I agree that having multiple functions with different signatures makes it more readable then having a single function with 20+ arguments all set to a default value (None
most of the time) and then having to fiddle around using endless if
, elif
, else
chains to find out what the caller actually wants our function to do with the provided set of arguments. This was long overdue following the Python Zen:
Beautiful is better than ugly.
and arguably also
Simple is better than complex.
Straight from the official Python documentation linked above:
from typing import overload
@overload
def process(response: None) -> None:
...
@overload
def process(response: int) -> Tuple[int, str]:
...
@overload
def process(response: bytes) -> str:
...
def process(response):
<actual implementation>
EDIT: for anyone wondering why this example is not working as you'd expect if from other languages I'd suggest to take a look at this discussion. The @overloaded
functions are not supposed to have any actual implementation. This is not obvious from the example in the Python documentation.
Upvotes: 99
Reputation: 5126
Python does not support method overloading like Java or C++. We may overload the methods, but we can only use the latest defined method.
# First sum method.
# Takes two argument and print their sum
def sum(a, b):
s = a + b
print(s)
# Second sum method
# Takes three argument and print their sum
def sum(a, b, c):
s = a + b + c
print(s)
# Uncommenting the below line shows an error
# sum(4, 5)
# This line will call the second sum method
sum(4, 5, 5)
We need to provide optional arguments or *args in order to provide a different number of arguments on calling.
Courtesy Python | Method Overloading
Upvotes: 5
Reputation: 349
In the MathMethod.py file:
from multipledispatch import dispatch
@dispatch(int, int)
def Add(a, b):
return a + b
@dispatch(int, int, int)
def Add(a, b, c):
return a + b + c
@dispatch(int, int, int, int)
def Add(a, b, c, d):
return a + b + c + d
In the Main.py file
import MathMethod as MM
print(MM.Add(200, 1000, 1000, 200))
We can overload the method by using multipledispatch.
Upvotes: 2
Reputation: 797
I just came across overloading.py (function overloading for Python 3) for anybody who may be interested.
From the linked repository's README file:
overloading is a module that provides function dispatching based on the types and number of runtime arguments.
When an overloaded function is invoked, the dispatcher compares the supplied arguments to available function signatures and calls the implementation that provides the most accurate match.
Features
Function validation upon registration and detailed resolution rules guarantee a unique, well-defined outcome at runtime. Implements function resolution caching for great performance. Supports optional parameters (default values) in function signatures. Evaluates both positional and keyword arguments when resolving the best match. Supports fallback functions and execution of shared code. Supports argument polymorphism. Supports classes and inheritance, including classmethods and staticmethods.
Upvotes: 5
Reputation: 4021
I think the word you're looking for is "overloading". There isn't any method overloading in Python. You can however use default arguments, as follows.
def stackoverflow(self, i=None):
if i != None:
print 'second method', i
else:
print 'first method'
When you pass it an argument, it will follow the logic of the first condition and execute the first print statement. When you pass it no arguments, it will go into the else
condition and execute the second print statement.
Upvotes: 18
Reputation: 429
Python added the @overload decorator with PEP-3124 to provide syntactic sugar for overloading via type inspection - instead of just working with overwriting.
Code example on overloading via @overload from PEP-3124
from overloading import overload
from collections import Iterable
def flatten(ob):
"""Flatten an object to its component iterables"""
yield ob
@overload
def flatten(ob: Iterable):
for o in ob:
for ob in flatten(o):
yield ob
@overload
def flatten(ob: basestring):
yield ob
is transformed by the @overload-decorator to:
def flatten(ob):
if isinstance(ob, basestring) or not isinstance(ob, Iterable):
yield ob
else:
for o in ob:
for ob in flatten(o):
yield ob
Upvotes: 2
Reputation: 2019
Python 3.x includes standard typing library which allows for method overloading with the use of @overload decorator. Unfortunately, this is to make the code more readable, as the @overload decorated methods will need to be followed by a non-decorated method that handles different arguments. More can be found here here but for your example:
from typing import overload
from typing import Any, Optional
class A(object):
@overload
def stackoverflow(self) -> None:
print('first method')
@overload
def stackoverflow(self, i: Any) -> None:
print('second method', i)
def stackoverflow(self, i: Optional[Any] = None) -> None:
if not i:
print('first method')
else:
print('second method', i)
ob=A()
ob.stackoverflow(2)
Upvotes: 3
Reputation: 61509
You can't, never need to and don't really want to.
In Python, everything is an object. Classes are things, so they are objects. So are methods.
There is an object called A
which is a class. It has an attribute called stackoverflow
. It can only have one such attribute.
When you write def stackoverflow(...): ...
, what happens is that you create an object which is the method, and assign it to the stackoverflow
attribute of A
. If you write two definitions, the second one replaces the first, the same way that assignment always behaves.
You furthermore do not want to write code that does the wilder of the sorts of things that overloading is sometimes used for. That's not how the language works.
Instead of trying to define a separate function for each type of thing you could be given (which makes little sense since you don't specify types for function parameters anyway), stop worrying about what things are and start thinking about what they can do.
You not only can't write a separate one to handle a tuple vs. a list, but also don't want or need to.
All you do is take advantage of the fact that they are both, for example, iterable (i.e. you can write for element in container:
). (The fact that they aren't directly related by inheritance is irrelevant.)
Upvotes: 23
Reputation: 5606
I write my answer in Python 3.2.1.
def overload(*functions):
return lambda *args, **kwargs: functions[len(args)](*args, **kwargs)
How it works:
overload
takes any amount of callables and stores them in tuple functions
, then returns lambda.functions[number_of_unnamed_args_passed]
called with arguments passed to the lambda.Usage:
class A:
stackoverflow=overload( \
None, \
#there is always a self argument, so this should never get called
lambda self: print('First method'), \
lambda self, i: print('Second method', i) \
)
Upvotes: 17
Reputation: 521
In Python, overloading is not an applied concept. However, if you are trying to create a case where, for instance, you want one initializer to be performed if passed an argument of type foo
and another initializer for an argument of type bar
then, since everything in Python is handled as object, you can check the name of the passed object's class type and write conditional handling based on that.
class A:
def __init__(self, arg)
# Get the Argument's class type as a String
argClass = arg.__class__.__name__
if argClass == 'foo':
print 'Arg is of type "foo"'
...
elif argClass == 'bar':
print 'Arg is of type "bar"'
...
else
print 'Arg is of a different type'
...
This concept can be applied to multiple different scenarios through different methods as needed.
Upvotes: 9
Reputation: 399
I write my answer in Python 2.7:
In Python, method overloading is not possible; if you really want access the same function with different features, I suggest you to go for method overriding.
class Base(): # Base class
'''def add(self,a,b):
s=a+b
print s'''
def add(self,a,b,c):
self.a=a
self.b=b
self.c=c
sum =a+b+c
print sum
class Derived(Base): # Derived class
def add(self,a,b): # overriding method
sum=a+b
print sum
add_fun_1=Base() #instance creation for Base class
add_fun_2=Derived()#instance creation for Derived class
add_fun_1.add(4,2,5) # function with 3 arguments
add_fun_2.add(4,2) # function with 2 arguments
Upvotes: 13
Reputation: 90742
In Python, you don't do things that way. When people do that in languages like Java, they generally want a default value (if they don't, they generally want a method with a different name). So, in Python, you can have default values.
class A(object): # Remember the ``object`` bit when working in Python 2.x
def stackoverflow(self, i=None):
if i is None:
print 'first form'
else:
print 'second form'
As you can see, you can use this to trigger separate behaviour rather than merely having a default value.
>>> ob = A()
>>> ob.stackoverflow()
first form
>>> ob.stackoverflow(2)
second form
Upvotes: 52
Reputation: 11534
In Python, you'd do this with a default argument.
class A:
def stackoverflow(self, i=None):
if i == None:
print 'first method'
else:
print 'second method',i
Upvotes: 7