Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Why return-type of itemgetter is not consistent

Python itemgetter doesn't return tuples of length 0 or 1. For example:

from operator import itemgetter

def get_something(keys):
    d = {
        "a": 1,
        "b": 2,
        "c": 3
    }
    return itemgetter(*keys)(d)

print(type(get_something(["a", "b"])))
# <class 'tuple'>
print(type(get_something(["a"])))
# <class 'int'>
print(type(get_something([])))
# TypeError: itemgetter expected 1 arguments, got 0 
  • Is there any good reason that the itemgetter is written this way? And not (1,) for the second last () and for the last?

  • Is there some other built-in option if I always want to return a tuple/list given the keys?

like image 299
Pekka Avatar asked Feb 26 '18 12:02

Pekka


2 Answers

Is there some other built-in option if I always want to return a tuple/list given the keys?

just use a comprehension:

[d[k] for k in keys]

In context:

from operator import itemgetter

def get_something(keys):
    d = {
        "a": 1,
        "b": 2,
        "c": 3
    }
    return [d[k] for k in keys]

print(get_something(["a", "b"]))
#[1, 2]
print(get_something(["a"]))
#[1]
print(get_something([]))
#[]
like image 197
Chris_Rands Avatar answered Oct 04 '22 00:10

Chris_Rands


Part of your confusion comes from the fact that your get_something() func takes a single argument (expected to be an iterable) and unpacks it when passing it to itemgetter(). This results in the return value of get_something() not being "symetric" with it's arguments.

If you defined get_something() to use varargs instead (as itemgetter() does) :

def get_something(*keys):
    d = {
        "a": 1,
        "b": 2,
        "c": 3
    }
    return itemgetter(*keys)(d)

the return values would be more consistant with the arguments, ie:

# ask for 3 keys, get 3 values:
>>> get_something("a", "b", "c")
(1, 2, 3)

# ask for 2 keys, get 2 values:
>>> get_something("a", "b")
(1, 2)

# ask for one key, get 1 value
>>> get_something("a")
1

# all of this with tuple unpacking in mind:

a, b = get_something("a", "b")
a = get_something("a") 

Now the point is that few people would bother using itemgetter() to implement your get_something function - itemgetter has mainly been designed to be used as a callback for sorted() and like functions / methods (where it's current behaviour makes sense), and get_something would more canonically be implemented with a list expression ie:

def get_something(keys):
    d = {
        "a": 1,
        "b": 2,
        "c": 3
    }
    return [d[k] for k in keys]

which would take an iterable and return a (possibly empty) list.

like image 43
bruno desthuilliers Avatar answered Oct 04 '22 00:10

bruno desthuilliers