To access an item in a dictionary, you use indexing: d["some_key"]. However, if the key doesn’t exist in the dictionary, a KeyError is raised. To avoid this, you can use .get and pass in a default value to return instead: d.get("some_key", "default value").
Lists don’t have such a method for safely indexing. There are many ways around it (as documented in many SO threads: thread 1, thread 2), but they’re all pretty awkward and they aren’t composable or chain-able the same way that .get() is.
This could maybe be applied to Tuples, but I’d prefer to keep scope small. And I don’t think this applies to Iterables in general, but I don’t know enough details about those to say.
I searched the threads and PEPs but not the mailing lists and I haven’t seen anything recommending this. I looked at the code and I think this shouldn’t be too hard to implement. I’d be willing to take a swing at it or writing a PEP if there’s any interest.
The .get() calls allow me to write a somewhat fluent and safe getter for the nested objects. But this blows up if the list is empty. To work around that, I have to store in a variable and then either check the length of the list or wrap the indexing in a try/except. If I’m using a variable index instead of a literal 0, then I need to use try/except because of negative indexes.
That’s a fairly complex example, but I think even the simple examples would benefit. For example, I want to look at the current item and the next item in a for loop. The following code blows up but with a safe get, it would do the “right” thing without blowing up:
lst = list(range(10))
for idx, item in enumerate(lst):
next_item = lst[idx + 1]
I know the argument that there are ways around these situations (see the SO threads linked above) or that a simple if/then is easy to use, so we shouldn’t bloat the standard library. I think that such an argument exists for dictionaries as well. Why can’t people just use if "some_key" in d: ret = d["some_key"] else: ret = "default value"?
Given that dict.get() is both used and loved enough to make people want it for list, I see great value in adding it to list.
Yeah. Part of the reasoning is that the situations where this would be useful are relatively rare, and are often best handled with a path-traversal function, such as:
def get(state, *path):
for step in path:
state = state[step]
get(state, "corp", "hand", 0, "title")
If you wanted, you could even make this a __getitem__ method on a class that always returns another instance of itself, although personally, I’d go for the simpler option of a helper function (since this sort of data often gets loaded/saved in JSON and it’s easier to use real dicts and lists).
That’s true, and the alternatives are fairly easy. It’s just nice to provide a built-in that makes specific use-cases easier, cover what looks like a gap in the api. Given that the first reply said it comes up “every now and again” and I found two heavily upvoted threads on Stack Overflow, I’d expect that to weigh a little bit for adding something to make this easier on folks (like me lol).
Fair enough, but that’s why I mentioned Sequence. That said, I’m not really familiar with how collections.abc registration works for built in / native collections like deque. Would it even “inherit” a method added to Sequence, or does registering only declare what interfaces it implements for isinstance checks?
Additionally I have been skimming docs for some other languages , and so far the proposed behavior isn’t as widespread as I assumed! At least not for a prominent method name like get.
C#/dotnet’s List<T> has the Enumerable.ElementAtOrDefault, but that’s an extension method, not defined directly on List or any of its parent interfaces
F#'s List.item throws an exception for out of bounds access; List.tryItem will return Optional.None but is clearly the secondary interface of the two
Java’s ArrayList.get throws, and none of the parent types in the collections package implement a ‘safe get’ method that return null as far as I can tell. The Collections helper class doesn’t include one either.
Swift’s Array indexing returns Self.Element not Self.Element? - i.e. is not nillable - and I don’t see any “safe get” method that supports specifying a default or returning nil. (The first and last properties are nillable, but that’s not arbitrary index access.)
Kotlin’s kotlin.collections.List has a get method (that backs the indexing operator , I think?) that requires in-bounds and I assume throws an exception otherwise. It does have extension methods similar to dotnet’s: getOrElse/getOrNull, and also (??? ) elementAtOrElse/elementAtOrNull.
Scala’s Vector[+A] is… it’s wild, and now I need to go learn Scala. 
Ruby’s Array seems to have nillable indexing by default (how fun!), and two alternative methods at and fetch - fetch can either throw an error or return a default, at seems under-documented 
TL;DR: I’ve convinced myself the proposed function isn’t as common as I thought.
…no methodology to speak of, suggestions welcome ↩︎
If someone can say why this is, I’d love to know ↩︎
apply works like ‘regular’ indexing (requires in-bounds), applyOrElse returns an Optional, and it also inherits orElse,and lift from PartialFunction that might be relevant? ↩︎
and Ruby is another hit list language that I don’t know much about yet… ↩︎
Rust’s get lets you chain functions from Option, so I guess there’s an obvious design reason they wouldn’t bother with a ‘default’ parameter overload for get. ↩︎
I am primarily a Clojure developer and it has the built-in functions get and get-in. Because Clojure is function-based, not method-based, get and get-in are polymorphic and work on any associative data structure (which includes Clojure’s vectors). They return nil when accessing out of bounds and they can be passed default values.
To prospective commenters, I know about the alternative ways to write my example code. I appreciate the enthusiasm but I linked to two SO threads that contain every suggestion posted so far. I created this thread to discuss whether to add something new to cover these alternatives. Seems prudent to stay on topic here.