Get Started Creating Youtube Shorts Google Help
>>> d = {'a':'b'} >>> d['a'] 'b' >>> d['c'] KeyError: 'c' >>> d.get('c', 'fail') 'fail' >>> l = [1] >>> l[10] IndexError: list index out of range Ultimately it probably doesn't have a safe .get method because a dict is an associative collection (values are associated with names) where it is inefficient to check if a key is present (and return its value) without throwing an exception, while it is super trivial to avoid exceptions accessing list elements (as the len method is very fast).
The .get method allows you to query the value associated with a name, not directly access the 37th item in the dictionary (which would be more like what you're asking of your list). Of course, you can easily implement this yourself: def safe_list_get (l, idx, default): try: return l[idx] except IndexError: return default You could even monkeypatch it onto the __builtins__.list constructor in __main__ , but that would be a less pervasive change since most code doesn't use it.
If you just wanted to use this with lists created by your own code you could simply subclass list and add the get method. Imran Python doesn't allow monkeypatching builtin types like list Nick Bastin @CSZ: .get solves a problem that lists don't have - an efficient way to avoid exceptions when getting data that may not exist.
It is super trivial and very efficient to know what a valid list index is, but there's no particularly good way to do this for key values in a dictionary.Mark Longair I don't think this is about efficiency at at all - checking if a key is present in a dictionary and / or returning an item are O(1) . It won't be quite as fast in raw terms as checking len , but from a complexity point of view they're all O(1) .
The right answer is the typical usage / semantics one...Nick Bastin @Mark: Not all O(1) are created equal. Also, dict is only best-case O(1), not all cases.Tyler Crompton I think that people are missing the point here. The discussion shouldn't be about efficiency. Please stop with the premature optimization. If your program is too slow, you are either abusing .get() or you have problems elsewhere in your code (or environment). The point of using such a method is code readability.
The "vanilla" technique requires four lines of code in every place that this needs to be done. The .get() technique only requires one and can easily be chained with subsequent method calls (e.g. my_list.get(2, '').uppercase() ). | This works if you want the first element, like my_list.get(0) >>> my_list = [1,2,3] >>> next(iter(my_list), 'fail') 1 >>> my_list = [] >>> next(iter(my_list), 'fail') 'fail' I know it's not exactly what you asked for but it might help others.
Eric less pythonic than functional programming-esque alphabetasoup next(iter(my_list[index:index+1]), 'fail') Allows for any index, not just 0. Or less FP but arguably more Pythonic, and almost certainly more readable: my_list[index] if index < len(my_list) else 'fail' .Yi Shen This way is ~2 times slower than the one-line if-else in Python 3.10.2 kaptan @YiShen can you provide your timing results here? Stef If you want the n th element, then you can do next(iter(my_list[n:n+1]), 'fail') Probably because it just didn't make much sense for list semantics.
However, you can easily create your own by subclassing. class safelist(list): def get(self, index, default=None): try: return self[index] except IndexError: return default def _test(): l = safelist(range(10)) print l.get(20, "oops") if __name__ == "__main__": _test() jose.angel.jimenez This is, by far, the most pythonic answering the OP. Note that you could also extract a sublist, which is a safe operation in Python. Given mylist = [1, 2, 3], you can try to extract the 9th element with mylist[8:9] without triggering an exception.
You can then test if the list is empty and, in case it is not empty, extract the single element from the returned list. Eric This should be the accepted answer, not the other non-pythonic one-liner hacks, especially because it conserves the symmetry with dictionaries. Jeyekomon There is nothing pythonic about subclassing your own lists just because you a need a nice get method. Readability counts. And readability suffers with every additional unnecessary class.
Just use the try / except approach without creating subclasses.Keith @Jeyekomon It's perfectly Pythonic to reduce boilerplate by subclassing. timgeb Why not return self[index] ? | Instead of using .get, using like this should be ok for lists. Just a usage difference. >>> l = [1] >>> l[10] if 10 < len(l) else 'fail' 'fail' ludo This fails if we try to get the latest element with -1. Tyler Crompton Note that this doesn't work for circularly linked list objects.
Additionally, the syntax causes what I like to call a "scanning block". When scanning through code to see what it does, this is a line that would slow me down for a moment. Eric inline if/else does not work with older python like 2.6 (or is it 2.5?) Nick Bastin @TylerCrompton: There is no circularly linked list in python.
If you wrote one on your own you are free to have implemented a .get method (except I'm not sure how you would explain what the index meant in this case, or why it would ever fail).mic An alternative that handles out-of-bounds negative indices would be lst[i] if -len(lst) <= i < len(l) else 'fail' Credits to jose.angel.jimenez, Gus Bus and Marek R For the "oneliner" fans… If you want the first element of a list or if you want a default value if the list is empty try: liste = ['a', 'b', 'c'] value = (liste[0:1] or ('default',))[0] print(value) returns a and liste = [] value = (liste[0:1] or ('default',))[0] print(value) returns default Examples for other elements… liste = ['a', 'b', 'c'] print(liste[0:1]) # returns ['a'] print(liste[1:2]) # returns ['b'] print(liste[2:3]) # returns ['c'] print(liste[3:4]) # returns [] With default fallback… liste = ['a', 'b', 'c'] print((liste[0:1] or ('default',))[0]) # returns a print((liste[1:2] or ('default',))[0]) # returns b print((liste[2:3] or ('default',))[0]) # returns c print((liste[3:4] or ('default',))[0]) # returns default Possibly shorter: liste = ['a', 'b', 'c'] value, = liste[:1] or ('default',) print(value) # returns a It looks like you need the comma before the equal sign, the equal sign and the latter parenthesis.
More general: liste = ['a', None, 'c'] f = lambda l, x, d='default': l[x] if -len(l) <= x < len(l) else d print(f(liste, 0)) # returns a print(f(liste, 1)) # returns None print(f(liste, 2)) # returns c print(f(liste, 3)) # returns default print(f(liste, -1)) # returns c More general with falsy management: liste = ['a', None, 'c'] f = lambda l, x, d='default': l[x] if -len(l) <= x < len(l) and l[x] not in (None, "", 0, False, [], {}, (), set(), frozenset(), b'', bytearray(b'')) else d print(f(liste, 0)) # returns a print(f(liste, 1)) # returns default print(f(liste, 2)) # returns c print(f(liste, 3)) # returns default print(f(liste, -1)) # returns c Tested with Python 3.6.0 (v3.6.0:41df79263a11, Dec 22 2016, 17:23:13) dreftymac +1 for reasonable approach with compact syntax, but an exception safe get() or get_at_index() might be a favorable and intuitive alternative, at least for those not yet comfortable with python slice notationBrandon Alternate syntax w/o trailing commas.
value = (lst[i:] or [None])[0] You have to use a trailing comma because it's telling python it's a tuple and not an expression wrapped in parens. So just use a list.David Maness This feels so hacky that I love it. Thanks for the cool idea. Not very "Pythonic", if you care about that kind of thing.
Try this: >>> i = 3 >>> a = [1, 2, 3, 4] >>> next(iter(a[i:]), 'fail') 4 >>> next(iter(a[i + 1:]), 'fail') 'fail' A reasonable thing you can do is to convert the list into a dict and then access it with the get method: >>> my_list = ['a', 'b', 'c', 'd', 'e'] >>> my_dict = dict(enumerate(my_list)) >>> print my_dict {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e'} >>> my_dict.get(2) 'c' >>> my_dict.get(10, 'N/A') tripleee A reasonable workaround, but hardly "the best thing you can do".
Marian Very inefficient though. Note: Instead of that zip range len thing, one could just use dict(enumerate(my_list)) erikbstack This is not the best thing, it's the worst thing you could do. Eric It's the worst thing if you consider performance... if you care about performance you don't code in an interpreted language like python. I find this solution using a dictionary rather elegant, powerful and pythonic. Early optimisations are evil anyway so let's have a dict and see later it it's a bottleneck.
So I did some more research into this and it turns out there isn't anything specific for this. I got excited when I found list.index(value), it returns the index of a specified item, but there isn't anything for getting the value at a specific index. So if you don't want to use the safe_list_get solution which I think is pretty good.
Here are some 1 liner if statements that can get the job done for you depending on the scenario: >>> x = [1, 2, 3] >>> el = x[4] if len(x) > 4 else 'No' >>> el 'No' You can also use None instead of 'No', which makes more sense.: >>> x = [1, 2, 3] >>> i = 2 >>> el_i = x[i] if len(x) == i+1 else None Also if you want to just get the first or last item in the list, this works end_el = x[-1] if x else None You can also make these into functions but I still liked the IndexError exception solution.
I experimented with a dummied down version of the safe_list_get solution and made it a bit simpler (no default): def list_get(l, i): try: return l[i] except IndexError: return None Haven't benchmarked to see what is fastest. Eric Not really pythonic. radtek @Eric which snippet? I think the try, except makes most sense by looking at it again. Eric A standalone function is not pythonic. Exceptions are a little more pythonic indeed but not by much as it's such a common pattern in programming languages.
What's much more pythonic is a new object that extends the builtin type list by subclassing it. That way the constructor can take a list or anything that behaves like a list, and the new instance behaves just like a list . See Keith's answer below which should be the accepted one IMHO.cowbert @Eric I parsed the question not as OOP-specific but as "why do lists have no analogy to dict.get() to return a default value from a list index reference instead of having to catch IndexError ?
So it really is about language/library feature (and not OOP vs. FP context). Furthermore, one probably has to qualify your use of 'pythonic' as maybe WWGD (as his disdain for FP Python is well known) and not necessarily just satisfying PEP8/20.mic el = x[4] if len(x) == 4 else 'No' – do you mean len(x) > 4 ? x[4] is out-of-bounds if len(x) == 4 . | Dictionaries are for look ups. It makes sense to ask if an entry exists or not. Lists are usually iterated.
It isn't common to ask if L[10] exists but rather if the length of L is 11. Mikhail M. Yes, agree with you. But I just parsed relative url of page "/group/Page_name". Split it by '/' and wanted to check if PageName is equal to certain page. It would be comfortable to write something like [url.split('/').get_from_index(2, None) == "lalala"] instead of making extra check for length or catch exception or write own function. Probably you are right it is simply considered unusual.
Anyway I still disagree with this =) Mikhail M. @Nick Bastin: Nothing wrong. It is all about simplicity and speed of coding. Antimony It would also be useful if you wanted to use lists as a more space efficient dictionary in cases where the keys are consecutive ints. Of course the existence of negative indexing already stops that.
This isn't an extremely general-purpose solution, but I had a case where I expected a list of length 3 to 5 (with a guarding if ), and I was breaking out the values to named variables. A simple and concise way I found for this involved: foo = (argv + [None, None])[3] bar = (argv + [None, None])[4] Now foo and bar are either the 4th and 5th values in the list, or None if there weren't that many values.
dreftymac despite the disclaimer attached to this answer, it is precisely a general-purpose solution if the goal is to ensure that a list as at least N elements, where N is an upper limit that is known at design time arantius At the time I was thinking it would be impractical for large indexes, but I suppose you could e.g.
(argv + [None]*999) .dreftymac exactly ^_^ dmid://uu966listinit1631296 bfontaine It’s simple to write but memory-wise it’s very inefficient If you - want a one liner, - prefer not having try / except in your happy code path where you needn't, and - want the default value to be optional, you can use this: list_get = lambda l, x, d=None: d if not l[x:x+1] else l[x] Usage looks like: >>> list_get(['foo'], 4) == None True >>> list_get(['hootenanny'], 4, 'ho down!') 'ho down!' >>> list_get([''], 0) '' For small index values you can implement my_list.get(index, default) as (my_list + [default] * (index + 1))[index] If you know in advance what index is then this can be simplified, for example if you knew it was 1 then you could do (my_list + [default, default])[index] Because lists are forward packed the only fail case we need to worry about is running off the end of the list.
This approach pads the end of the list with enough defaults to guarantee that index is covered. Your usecase is basically only relevant for when doing arrays and matrixes of a fixed length, so that you know how long they are before hand. In that case you typically also create them before hand filling them up with None or 0, so that in fact any index you will use already exists. You could say this: I need .get() on dictionaries quite often.
After ten years as a full time programmer I don't think I have ever needed it on a list. :) Mikhail M. How about my example in comments? What is more simple and readable? (url.split('/').getFromIndex(2) == "lalala") OR (result = url.split(); len(result) > 2 and result[2] == "lalala"). And yes, I know I can write such function myself =) but I was surprised such function is not builtin. Lennart Regebro Id' say in your case you are doing it wrong.
URL handling should be done either by routes (pattern matching) or object traversal. But, to answer your specific case: 'lalala' in url.split('/')[2:] . But the problem with your solution here is that you only look at the second element. What if the URL is '/monkeybonkey/lalala'? You'll get a True even though the URL is invalid.Mikhail M. I took only second element because i needed only second element.
But yes, slices seem good working alternative Lennart Regebro @CSZ: But then the first element is ignored, and in that case you could skip it. :) See what I mean, the example doesn't work that well in real life. l[10:11] instead ofl[10] , for example. ()Th sublist will have the desired element if it exists).get . It would be the equivalent ofl[i] if i < len(l) else default , but more readable, more concise, and allowing fori to be an expression without having to recalculate itNone if one didn't exist.
It would have been nice to sayx = expensive().get(0, None) so I wouldn't have to put the useless return of expensive into a temporary variable.mylist.get(myindex, mydefault) was rejected in favor of(mylist[myindex:myindex+1] or mydefault)[0] :-/
People Also Asked
- Understanding .get() method in Python - Stack Overflow
- Understanding dictionary.get in Python - Stack Overflow
- What is the "get" keyword before a function in a class?
- Why doesn't list have safe "get" method like dictionary?
- Understanding __get__ and __set__ and Python descriptors
- YouTubeShortsProduction Workflow — Grokipedia
- CreatingFillable Form On Adobe
- CreatingLine Plots With Fractions - Printable Templates Free
Understanding .get() method in Python - Stack Overflow?
If you just wanted to use this with lists created by your own code you could simply subclass list and add the get method. Imran Python doesn't allow monkeypatching builtin types like list Nick Bastin @CSZ: .get solves a problem that lists don't have - an efficient way to avoid exceptions when getting data that may not exist.
Understanding dictionary.get in Python - Stack Overflow?
Marian Very inefficient though. Note: Instead of that zip range len thing, one could just use dict(enumerate(my_list)) erikbstack This is not the best thing, it's the worst thing you could do. Eric It's the worst thing if you consider performance... if you care about performance you don't code in an interpreted language like python. I find this solution using a dictionary rather elegant, powerful ...
What is the "get" keyword before a function in a class?
If you wrote one on your own you are free to have implemented a .get method (except I'm not sure how you would explain what the index meant in this case, or why it would ever fail).mic An alternative that handles out-of-bounds negative indices would be lst[i] if -len(lst) <= i < len(l) else 'fail' Credits to jose.angel.jimenez, Gus Bus and Marek R For the "oneliner" fans… If you want the first ele...
Why doesn't list have safe "get" method like dictionary?
The .get method allows you to query the value associated with a name, not directly access the 37th item in the dictionary (which would be more like what you're asking of your list). Of course, you can easily implement this yourself: def safe_list_get (l, idx, default): try: return l[idx] except IndexError: return default You could even monkeypatch it onto the __builtins__.list constructor in __mai...
Understanding __get__ and __set__ and Python descriptors?
More general: liste = ['a', None, 'c'] f = lambda l, x, d='default': l[x] if -len(l) <= x < len(l) else d print(f(liste, 0)) # returns a print(f(liste, 1)) # returns None print(f(liste, 2)) # returns c print(f(liste, 3)) # returns default print(f(liste, -1)) # returns c More general with falsy management: liste = ['a', None, 'c'] f = lambda l, x, d='default': l[x] if -len(l) <= x < len(l) and l[x]...