5

I have this simple program that is supposed to sort the array of arrays by the key.

Why is the sorted() function saying that it only takes 1 argument, and that I am not providing any?

import operator

array = [[1, 6, 3], [4, 5, 6]]
sorted_array = sorted(iterable=array, key=operator.itemgetter(array[0][1]), reverse=True)
print(sorted_array)

And the error this gives:

Traceback (most recent call last):
  File "...", line 4, in <module>
    sorted_array = sorted(iterable=array, key=operator.itemgetter(array[0][1]), reverse=True)
TypeError: sorted expected 1 argument, got 0
Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
Jake West
  • 131
  • 7

2 Answers2

8

Your confusion is justified. The error:

TypeError: sorted expected 1 argument, got 0

is a bit confusing to begin with. What it actually means is:

sorted expected 1 [positional] argument, got 0

Looking at the docs, the signature is:

sorted(iterable, *, key=None, reverse=False)

According to this, a bare * in a function's signature means that all following arguments must be named. That doesn't say anything about the preceding arguments.

When printing help(sorted) in an interactive shell gives the more accurate signature:

sorted(iterable, /, *, key=None, reverse=False)

According to this, a / in a function's signature means that all preceding arguments must be positional, i.e. not named, which now explains the error. You just need to pass the array as a positional argument:

sorted_array = sorted(array, key=..., reverse=True)

Please refer to @Rivers' answer for the correct use of itemgetter as the key.


I have reported this documentation issue on the official Python bug tracker.

Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
  • What's the logic behind now being able to say `iterable = array` in the function call for `sorted`? In general, why would the developer not allow a certain argument to be named in the call? – bob Feb 22 '23 at 15:53
  • This is just my personal view - as with the sorted example, the named arguments are like "settings". What key tonuse, should it be reversed etc. It makes sense and is more readable to have them named (only). The caller can omit some, use whatever order etc. Tne first argument is the input list. It should always come first. To me that makes *some* sense. There must be some SO question disccusing this that I will to to find later – Tomerikoo Feb 23 '23 at 20:15
1

I'll try to give you a clear and detailed explanation:

There are 2 problems:

  1. iterable is not a named parameter
  2. itemgetter syntax is wrong

1 - Iterable:

This is the definition of the sorted function (see https://docs.python.org/3/library/functions.html#sorted): sorted(iterable, *, key=None, reverse=False)

Perhaps you thought that iterable is a named parameter, but it isn't. The named parameters are key and reverse (they have the equal sign (=) after their names).

So you don't have to write iterable=something. You just have to give an iterable data structure, so in your example that's the variable named array:

sorted_array = sorted(array,...)

Update: See @Tomerikoo answer for the exact reason why this didn't work in this case.

2 - Itemgetter: You can't write itemgetter(array[0][1]), you just have to give the indexes of the elements, so as @Ajay wrote in his comment, you could write this instead:

itemgetter(0,1)

But if you really want to sort by array[0][1], you should use a lambda function as @Ajay wrote too.

All in one:

from operator import itemgetter

array = [[1,6,3], [4,5,6]]
sorted_array = sorted(array, key=itemgetter(0,1), reverse=True)
print(sorted_array)

Output:

[[4, 5, 6], [1, 6, 3]]
Rivers
  • 1,783
  • 1
  • 8
  • 27