Add Optional Index Access Operator `?[]`

Python developers frequently need to check if an index is valid before accessing a list.
Instead of adding a condition, this proposal offers a short and convenient syntax for index checking.

Current Approach:

# Currently, developers need to write:
if i < len(my_list) and my_list[i]:
    process(my_list[i])

Proposed Syntax:

if my_list[i?]:
    process(my_list[i])

Recent discussions:

1 Like

I think it would be much more realistic that anything happens in this direction if it would not use a new syntax. Additionally, your proposal does not tell how it interacts with slices, neither does it say what actually the return value is if the index is not in the range.

One could consider adding a new method say get_or to the standard library containers (like tuple, list, dict, bytearray, bytes, string) with the desired behavior. That method should also be explicit with what happens if the the index is out of range. Slices could be explicitly forbidden. The method could work as follows:

    def get_or(self, index, alternative, /):
        if isinstance(index, slice):
            raise TypeError("Index must be an integer")
        try:
            return self[index]
        except IndexError:
            return alternative

Since the container classes are written in C, this function would have the be written in C as well.

2 Likes

You should move this conversation to the Python Ideas section. This section is for people who want help with their Python code. The Python Ideas section will be able to help you and discuss this idea a lot more.

2 Likes

Moved to ideas.

This more or less exactly what the dict.get method does, and I remember there somewhat recently being a thread here about adding it to lists. However, there was no consensus in the thread.

3 Likes

It was initially posted in ideas, and I moved it to general. The Python Help category is “General help/discussion forum”, which is not exclusively for help but is so named to ensure that help posts find the right place.

There have previously been extensive discussions about the purposes of the ideas section, and posts like this tick a number of boxes that people were hoping to reduce. It is a short post that demonstrates little consideration of the scope of the proposal and it fails to engage with the existing discussions on the topic.

Unfortunately, these discussions have largely happened in inappropriate ideas posts, which makes them hard to search for, for people who aren’t regularly reading. A couple threads that are a slog to get through but are directly on the topic:

5 Likes

Thanks, I have missed that dict has already such a member. So, providing the same functionality also for other containers would actually make the standard library more consistent.

I also found the discussion you were likely referring to:

This is a bit old news. I think the resulting actions that came out of it were:

Utilities of these 2 will cover this. I.e. getitem(..., default=) and itemgetter(..., default=) and its iterator argument counterpart gititeritem & itemitergetter, which will allow for default iterable argument.

Anything more complex than that any time soon is unlikely. Be it list.get (which is quite hefty implementation with fair amount of issues with sequence protocol) or custom operators.

1 Like

I meant that if the index is out of range, list.get(index) would return None.
Yes, it is somewhat similar to how dict.get(key) works.

I’m really unsure about what is more intuitive: list[i?] or list.get(i).
On one hand, get would align with how dictionaries work.
On the other hand, get is often associated with keys, so it might be confusing when dealing with indices.

In short, shorthand you desire will (most likely) be available via:

from operator import getitem

if (item := getitem(my_list, i, None)) is not None:
    process(item)
1 Like

Developers neither need to nor should write such code or find themselves in that position.

However, they should use try/except:

try:
    process(my_list[i])
    
except IndexError:
    pass

On the other hand, get is often associated with keys, so it might be confusing when dealing with indices.

Indices are a special case of keys. A dict is a mapping key->value, a list is a mapping index->value. In both cases, you can access the items with the same syntax: v[n], where n is either an index or a key, depending on the type of v. This is not confusing. Why should a member function get be confusing?

Quite opposite: member functions are already there and well understood. In a good language design, the member functions of similar types (like containers) should actually be aligned since this allows, e.g., for generic code.

A new syntax is never so obvious. It is by no means clear for a programmer who first encounters the expression v[n?] that the question mark ? is part of the array access operator [], as opposed to being a postfix unitary operator that is applied to n. You cannot even search nicely for a syntax! It is also no obvious how to name [1] a new syntax.


  1. In the title of this thread, you called it “Optional Index Access Operator ?[]”. That syntax is obviously different from the syntax that you have actually proposed, which looks like [ ?]. ↩︎