1

My book says that function overloading is not possible in python but it asks me questions like:

WAP to find out the volume of a cube,cuboid and cylinder using function overloading.

Do I have to involve decorators here?

How am I supposed to involve functional overloading in my program?

I saw a similar question where wraps from functools was used but failed to understand it.

If functional overloading is not involved then it is child's play...

P.S-I am in grade 12 and we haven't been taught much about decorators.

4
  • 2
    What book are you using? Is it intended to be used with Python? It might just be a bad book. – Daenyth Dec 7 '15 at 17:34
  • You can fake function overloading pretty easily with a **kw argument, though it is not clear that's what is being asked by the book. True function overloading does not exist in Python. – Gort the Robot Dec 7 '15 at 21:28
  • My book is a standard book issued by the govt of india(cbse)...and by the way this question is in many of the other indian books...but as shenshin said even i think its been copied from some c++ book as python is just introduced to curriculum... And c++ supports function overloading so the code is easy there..... – geek101 Dec 8 '15 at 19:40
  • I tried doing this problem with an abstract method....it worked ! That could be an alternative solution. – geek101 Dec 8 '15 at 19:46
4

If you're using Python 3.4 or newer, you have access to functools.singledispatch (thanks to PEP 443), which lets you overload functions (preferably unary) much like you would in a language like Java.

If you define your various polyhedra as classes, you can dispatch on their types, like so:

import math
from functools import singledispatch


class Cube:
    def __init__(self, x):
        self.x = x

class Cuboid:
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

class Cylinder:
    def __init__(self, *, r, h):
        self.r = r
        self.h = h

# Mark this function as single-dispatchable.
@singledispatch
def volume(polyhedron):
    pass # Or throw an exception, or something like that.

def _volume_cube(cube):
    return cube.x ** 3

def _volume_cuboid(cuboid):
    return cuboid.x * cuboid.y * cuboid.z

def _volume_cylinder(cylinder):
    return math.pi * (cylinder.r) ** 2 * cylinder.h

# Register handlers for the types for which you can compute volumes.
volume.register(Cube, _volume_cube)
volume.register(Cuboid, _volume_cuboid)
volume.register(Cylinder, _volume_cylinder)

Now, you can do this:

>>> cube = Cube(4)
>>> volume(cube)
64
>>> cuboid = Cuboid(3, 5, 7)
>>> volume(cuboid)
105
>>> cylinder = Cylinder(r=2, h=4)
>>> volume(cylinder)
50.26548245743669

If you're using a version older than 3.4, you don't really have any good options for this sort of transparent single dispatch (though you could always just backport functools.singledispatch if you're on an earlier 3.x - it's written in pure Python and I don't think it relies on any new 3.4 features). You could, instead, have a function volume(cube=None, cuboid=None, cylinder=None), or volume(polyhedron) and dispatch on type(polyhedron) inside the function, or do some magic with **kwargs.

All that said, I somehow doubt that your book wants you to use functools.singledispatch - I'd hazard a guess that somebody just copied the problems out of a C++ or Java book without really thinking about it.

1

It's possible the book is using incorrect wording and is actually asking you to use OO inheritance.

class Shape(object):
    def volume():
        raise NotImplementedError()

class Cube(Shape):
    def __init__(self, side_length):
        self.side = side_length
    def volume():
        return self.side * self.side * self.side

class Cylinder(Shape):
    def volume():
        ...
1

Python does not support function overloading, however, it does give you the tools to implement it yourself in a fairly straightforward manner.

Using **kw in the parameter list will pass all arguments in a dictionary. In order to simulate function overloading, you test for the existence of parameters yourself and dispatch appropriately:

def foo_x_y(x, y):
    print("x is %d y is %d" % (x,y))

def foo_h_l(h, l):
    print("h is %d l is %d" % (h,l))

def foo(**kw):
    if 'x' in kw and 'y' in kw:
        return foo_x_y(kw['x'], kw['y'])
    elif 'h' in kw and 'l' in kw:
        return foo_h_l(kw['h'], kw['l'])

    raise TypeError("foo() takes exactly 2 argument (%d given)" % len(kw))


>> foo(x=1, y=2)
x is 1 y is 2
>> foo(h=2, l=1)
h is 2 l is 1
>> foo(z=1)
File "foo.py", line 18, in <module>
   foo(z=1)
File "foo.py", line 13, in foo
   raise TypeError("foo() takes exactly 2 argument (%d given)" % len(kw))
TypeError: foo() takes exactly 2 argument (1 given)

This takes more legwork, but is more flexible than overloading. It makes it easier to "overload" in ways that involve a single core implementation, for example:

def arc_length(**kw):
    if 'diameter' not in kw:
        raise TypeError

    if 'radians' not in kw or 'degrees' not in kw:
        raise TypeError

    if 'radians' in kw and 'degrees' in kw:
        raise TypeError

    diameter = kw['diameter']

    if degrees in kw:
        radians = degrees_to_radians(kw['degrees'])
    else:
        radians = kw['radians'] 

    # calculate arc length using radians and diameter

 arc_length(diameter=10, degrees=30)
 arc_length(diameter=10, radians=1.2)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.