Indexable get method. [1,2,3].get(4) # None

After a bit of research, I found that this idea was suggested back in 2018, but the conversation stopped, and the topic was automatically closed.

Links to the original discussion:

I think it would be great to add a few more spoons of syntactic sugar for working with lists and other indexable objects. The idea is pretty simple to implement and doesn’t require major changes.

Currently, you might write:

myval = mylist[1] if len(mylist) > 1 else None
# or
try:
    myval = mylist[1]
except IndexError:
    myval = None

But wouldn’t it be cleaner and simpler to have:

myval = mylist.get(1)

A lot of people on Stack Overflow are asking about this functionality, and I agree it’s not an uncommon case. Maybe it’s time to take a second look at this idea? What do you think?

16 Likes

I like that this proposal follows the pattern established by dict.get(...). I could see myself using it.

10 Likes

It seems nice and clean and consistent with dict.

Are there many use cases after a list.get call that don’t require a subsequent test such as: if myval is None (or if myval =='Sentinel' if None is in the list)?

2 Likes

PEP 463 would like to say hi, too. Its rejection may provide some insights.

5 Likes

I like to do [myval] = mylist[1:2] or [None]

Nice hack, but may be confusing for those not deeply familiar with Python

3 Likes

Can you show the motivating code where you want to do this?

Do you have examples? I don’t remember ever seeing that.

Case when some APIs return an empty list or a list with exactly one element, or if you need only the first element because the target structure doesn’t have a field for more than one:

response = requests.get("https://example.com")
phone_list = response.json()['phone']
phone_number = phone_list[0] if phone_list else None

A case with some libraries that return only batches when you need only the first element: For example, face detection algorithms might return a list of detected rectangles, but you might only care about the first one. (This is not the best example because, in the case of face detection, you might want to process 2+ detections separately; however, I can’t think of a better one at the moment.)

detected_faces = some_cv_lib.detect_faces('foo.jpg')
first_face = detected_faces[0] if detected_faces else None

Can’t provide enough examples because of 2 links limitation. There’s 5 links in the original discussion. And I can find few dozens more with google queries like ‘safe get method for list python’.

Also I found that this idea was already posted here in 2023 Add safe `.get` method to List - #3 by NoahTheDuke And even discussion with answer from Guido van Rossum Mailman 3 What about having a .get(index, default) method for arrays like we have for dicts? - Python-ideas - python.org

So maybe it’s time to close this topic

1 Like

Like this:

phone_number = phone_list[0] if phone_list else None

I fully support this, for tuples as well.

I’m a big fan of duck typing. I don’t use any type-checking tools and would never want to get into the kinds of messes that I see others create with them; but I sometimes annotate my interfaces as documentation, and use collections.abc typenames to do so. If I write something that conceptually expects an immutable mapping of integers to whatever, I’d like to be able to accept a list - or a tuple - transparently. That kind of thing is a big part of why I use Python. Having a .get method would help support my style of programming.

4 Likes

This seems like much more of a “mess” than using type checking and having guarantees about what you can and can’t pass, and what a function accepting something can and can’t do.

That said, you can just pass dict(enumerate(x)) to convert a list[T] to a Mapping[int, T].

It doesn’t happen very often to me, but it does happen consistently. From time to time I am doing something and I find myself in a place where it is somewhat obvious that get of list would be the “one best way to do it”.

The last one (few minutes ago):

if args and args[-1] is VOID:
    raise
# Alt
if args.get(-1, None) is VOID:
    raise

Over the last year I have encountered around 4-5 such uncorrelated occurrences.

This is not very pleasant for inline usage:

if ([myval] = mylist[1:2] or [None])[0] is None:
    ...
1 Like

Did anyone read through the thread on mailman 3? Mailman 3 get() method for list and tuples - Python-ideas - python.org
I’m not too motivated to summarize it, as my previous summaries didn’t lead anywhere.

This is what immediately stands out though:

alist = []
y = alist.setdefault(10, 'a')  # Raise error?

Stands out in what way?

The person was also suggesting to support list.setdefault() & tuple.setdefault(), but I’m not sure what that would even do…

What immediately stood out to me was the comment:

I’ve written my own version […] but then struggled to find a good use for it. It seems like it ought to
be useful, but in practice I found that it was only covering up bugs in my code.

This is an extremely good test of an idea. If you write your own version, and then find that you don’t use it (because it’s not worth the effort to import it, or because what you need isn’t quite the same as the version you wrote, or for some other reason) then maybe the idea wasn’t as good in practice as you hoped it would be.

2 Likes

This can be a good test, but don’t think this is decisive factor for all cases (not even majority in my case).

I don’t use a lot of what I could implement in python due to couple of reasons:
a) Performance
b) I try to use constructs provided by standard library as much as possible. Otherwise, I have a lot of code that becomes obsolete once a good solution becomes available in standard library.

E.g. my above example:

if args and args[-1] is VOID:
    raise
# Alt
if args.get(-1, None) is VOID:
    raise

And there are a lot of python features that if were not implemented I would use next best method in standard library instead of implementing my own.

E.g. dict.get

Would I write my own function?

def dict_get(...):
    ...
a = dict_get(d, default)

Ow would I just?

a = d[k] if k in d else default

Does it mean, that dict.get is unnecessary method?

1 Like

… wouldn’t you just use if k not in d ? Or perhaps if k not in d or d[k] is default ?