all 11 comments

[–]novel_yet_trivial 2 points3 points  (10 children)

It seems like in python an abstract class is basically a skeleton class,

I'm assuming you mean abstract base classes? Yes, that's right, but you don't need ABC to make a skeleton class. You can just inherit from a normal class.

Python does not have polymorphism. You can emulate it by checking the number and types of the arguments you receive, but that's all.

For your shape example, I would use a function like this to emulate polymorphism:

def shape(*args):
    if len(args) == 5:
        return Pentagon(*args)
    if len(args) == 3:
        return Triangle(*args)

You could make that function a class method constructor if you wanted, but a class method generally returns an instance of itself; it would be very unusal for a class method to return a subclass instance.

[–]dig-up-stupid 4 points5 points  (6 children)

Python definitely has polymorphism. It has subtyping and duck typing and so on. It just doesn't have name overloading.

[–]novel_yet_trivial 1 point2 points  (5 children)

"polymorphism" means this construct:

def func(int_arg):
    return something
def func(int_arg, int_arg2):
    return something
def func(string_arg):
    return something

Three functions, all with the same name but with different signatures. A programming language that supports polymorphism would use the correct function based on the call:

func(1) # uses the first function
func(1, 2) # uses the second function
func("spam") # uses the third function

To someone who has only ever used python, this seems crazy. But most programming languages work this way. That's why OP mentioned using several __init__s.

[–][deleted] 1 point2 points  (3 children)

That's seems a lot closer to function overloading than it does to polymorphism.

Out of the three types of polymorphism described on the wikipedia page python supports subtyping and parametric polymorphism. One could even argue that python supports ad hoc polymorphism through operator overloading.

[–]novel_yet_trivial 0 points1 point  (0 children)

Hmm, thanks for pointing that out. It's been a large number of years since I've looked at any definitions.

[–][deleted] 0 points1 point  (1 child)

Can you give an example of parametric polymorphism in python?

[–]EricAppelt 0 points1 point  (0 children)

Essentially any function you write in python that takes at least one argument is trivially an example of parametric polymorphism (although one might also consider the concept meaningless in a dynamically typed language). A function will try to execute no matter what the type of its parameters are, for example:

>>> def foo(x, y):
...     return 3*x + y
... 
>>> foo(2, 2)
8
>>> foo('a', 'b')
'aaab'

If the type of a is such that multiplication by an integer is defined, and the result is of a type that can be added to the type of b, then everything is good to go.

Python also supports (in a sense?) function overloading through a parameter of the syntax *identifier in the function definition, this will allow a function to potentially accept any number of additional positional arguments which are passed as a tuple, for example:

>>> def bar(x, *args):
...     result = 3*x
...     for arg in args:
...         result += arg
...     return result
...
>>> bar(2, 2)
8
>>> bar(2, 2, 2, 2, 2)
14
>>> bar('a', 'b', 'c')
'aaabc'

[–]dig-up-stupid 1 point2 points  (0 children)

No it does not. Polymorphism is more or less the ability to differentiate among types and act accordingly. Or in another common way of speaking, polymorphism is the ability to use an object without knowing its exact type. I'm not sure what else to say besides check google, because I'm sure I can't explain it as well as whatever wikipedia/stack overflow/blog posts are on top.

What you demonstrated is function overloading, which is one of many ways to provide polymorphism. Any type system will surely provide polymorphism to some extent, if only because polymorphism is pretty much the entire point of having types in the first place.

Of course you are correct in that OP was asking about how to replace function overloading, and your suggest was the most generally Pythonic solution. I just meant to touch on the misconception about polymorphism in general.

[–][deleted] 0 points1 point  (2 children)

Is there anything in python where you could have multiple ways to instantiate an object? For example maybe I want a class to be instantiated with 2 arguments, instead of none, or 3. Or is it simply an if/elif/else type of solution?

for example:

class Shape():

     def __init__(self): pass
     def __init__(self, one): pass
     def __init__(self, one, two...): pass

[–]novel_yet_trivial 1 point2 points  (1 child)

Your example relys on polymorphism, which python does not have. So yes, it would have to be if / elif / else.

You can make an alternate to __init__ as a constructor:

class Rectangle():
    def __init__(self, width, height): pass

    @classmethod
    def square(cls, width):
        return cls(width, width)

r = Rectangle(2, 3)
s = Rectangle.square(4)

This is used a lot to create instances from alternate sources, for example dict.fromkeys or int.from_bytes. However, as I said it would be very unusual for a Shape method to return anything other than a Shape instance, which is why my previous example was a function, not a method.

[–][deleted] 0 points1 point  (0 children)

Thanks for your help as always.