Determine if a triangle is equilateral, isosceles, or scalene I've been fiddling around with some easy code challenges and there's one about determining if a triangle is equilateral, isosceles, or scalene.

I've come up with a working solution, but I feel this could be greatly improved and/or simplified.

The sides of a triangle come in a list e.g. [2, 2, 2] or [0, 0, 0]. 

Here's what I've got.

def is_triangle(sides):
    if min(sides) &lt;= 0:
        return False
    if sum(sorted(sides)[:-1]) &lt; sorted(sides)[-1]:
        return False
    return True


def equilateral(sides):
    triangle = is_triangle(sides)
    if triangle:
        x, y, z = sides
        return x == y == z
    else:
        return False


def isosceles(sides):
    triangle = is_triangle(sides)
    if triangle:
        x, y, z = sides
        return x == y or y == z or z == x
    else:
        return False


def scalene(sides):
    if equilateral(sides) or isosceles(sides):
        return False
    return is_triangle(sides)


Also, I'm adding a simple unit test module.

import unittest

from triangle import equilateral, isosceles, scalene

class TestEquilateralTriangle(unittest.TestCase):
    def test_all_sides_are_equal(self):
        self.assertIs(equilateral([2, 2, 2]), True)

    def test_all_zero_sides_is_not_a_triangle(self):
        self.assertIs(equilateral([0, 0, 0]), False)

    def test_third_triangle_inequality_violation(self):
        self.assertIs(isosceles([3, 1, 1]), False)

    def test_sides_may_be_floats(self):
        self.assertIs(equilateral([0.5, 0.5, 0.5]), True)


class TestIsoscelesTriangle(unittest.TestCase):
    def test_last_two_sides_are_equal(self):
        self.assertIs(isosceles([3, 4, 4]), True)

    def test_equilateral_triangles_are_also_isosceles(self):
        self.assertIs(isosceles([4, 4, 4]), True)

    def test_third_triangle_inequality_violation(self):
        self.assertIs(isosceles([3, 1, 1]), False)

    def test_sides_may_be_floats(self):
        self.assertIs(isosceles([0.5, 0.4, 0.5]), True)


class TestScaleneTriangle(unittest.TestCase):
    def test_no_sides_are_equal(self):
        self.assertIs(scalene([5, 4, 6]), True)

    def test_all_sides_are_equal(self):
        self.assertIs(scalene([4, 4, 4]), False)

    def test_third_triangle_inequality_violation(self):
        self.assertIs(isosceles([3, 1, 1]), False)


if __name__ == "__main__":
    unittest.main()


I'd appreciate some feedback on my code.
A triangle has, by definition, three sides. I find it therefore weird to take a single sides argument, which could be of any size. This opens you up to obscure bugs, such as these ones, which are not covered in your tests:

&gt;&gt;&gt; is_triangle([1,2,3,4])
True    # ?
&gt;&gt;&gt; is_triangle([1, 1])
True    # ???
&gt;&gt;&gt; is_triangle([float('nan')])
True    # WTF?


Instead, just explicitly take three arguments. The sides of a triangle are customarily called a, b, c.

def is_triangle(a, b, c):
    a, b, c = sorted([a, b, c])
    return a &gt; 0 and a + b &gt; c


This uses the fact that after the sorted, a is always the smallest side, as mentioned in the comments.

The only thing you need to change in your calling code is to call this with is_triangle(*sides), i.e. use tuple unpacking.



Your other functions can also be shortened a bit. Try to put multiple checks in one line to return right away (but don't push it if it gets too complicated).

def equilateral(a, b, c):
    return is_triangle(a, b, c) and a == b == c


Instead of manually checking all combinations of sides for equality, just use set to get rid of multiples:

def isosceles(a, b, c):
    return is_triangle(a, b, c) and len(set([a, b, c])) &lt;= 2

def scalene(a, b, c):
    return is_triangle(a, b, c) and len(set([a, b, c])) == 3




Note that all functions need to use is_triangle. You could define a decorator that makes sure the input is a triangle:

from functools import wraps

def ensure_triangle(func):
    @wraps(func)
    def wrapper(a, b, c):
        return is_triangle(a, b, c) and func(a, b, c)
    return wrapper

@ensure_triangle
def equilateral(a, b, c):
    return a == b == c

@ensure_triangle
def scalene(a, b, c):
    return len(set([a, b, c])) == 3

@ensure_triangle
def isosceles(a, b, c):
    return len(set([a, b, c])) &lt;= 2