TL;DR: You can sort twice, adding a reversed=True argument where needed. Sort by the tiebreaker first. This works because sorting is stable in Python.
Using - attribute2 instead of attribute2 inside the tuple is the easiest way if attribute2 is a number.
If attribute2 is a string, or something else that cannot be multiplied by -1 in a meaningful way, then this trick doesn't work.
However, note that lst.sort and sorted are guaranteed to be stable sorts in python. In particular, this means that the two following code snippets are equivalent:
# SORT ACCORDING TO A TUPLE
l.sort(key=lambda x: (x[0], x[1]))
# SORT TWICE
l.sort(key=lambda x: x[1])
l.sort(key=lambda x: x[0])
Note how in the second version, we sorted by the tie-breaker first, then by the main criterion.
With the first version, we can sort in decreasing order of one of the two criterion by multiplying it by -1, if this criterion is numeric:
l.sort(key=lambda x: (x[0], -x[1]))
With the second version, however, we can sort in decreasing order of one of the two criterion, using optional argument reverse=True, and this works for numbers as well as for other types, for instance strings.
l.sort(key=lambda x: x[1], reverse=True)
l.sort(key=lambda x: x[0])
Finally, note that instead of defining a custom function with def or lambda to use as the sorting key, you can use operator.itemgetter or operator.attrgetter.
For instance, the following two code snippets are equivalent:
# FIRST VERSION
l.sort(key=lambda x: (x[0], x[1]))
# SECOND VERSION
from operator import itemgetter
l.sort(key=itemgetter(0, 1))
The following three code snippets are equivalent:
# FIRST VERSION
def mykey(x):
x1 = x.attribute1
x2 = x.attribute2
return (x1, x2)
l.sort(key=mykey)
# SECOND VERSION
l.sort(key=lambda x: (x.attribute1, x.attribute2))
# THIRD VERSION
from operator import attrgetter
l.sort(key=attrgetter('attribute1', 'attribute2'))