Determine if a triangle is equilateral, isosceles, or scalene
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