-1

Considering below example,

myList = [1, 2, 3, 4, 5, 6]

To print last index,

# Non - pythonic
if len(myList) >= 6:
   print(myList[5])
else:
   print('Index does not exist')

# Pythonic
try:
   print(myList[5])
except:
   print('Index does not exist')

What is the idea behind the preference to ask for forgiveness over taking permission?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
overexchange
  • 15,768
  • 30
  • 152
  • 347
  • https://docs.python.org/3/glossary.html#term-eafp – jonrsharpe May 21 '17 at 12:35
  • In general there are a lot of ways you can get the LBYL method (look before you leap) wrong, and the technique can even result in race conditions. http://stackoverflow.com/questions/9748678/which-is-the-best-way-to-check-for-the-existence-of-an-attribute/9748715#9748715 – Dietrich Epp May 21 '17 at 12:39
  • 2
    You also need to take into account that some cases you can't know the pre-condition for success of what you're trying (and that pre-condition may even become invalid between the test and attempt). So using exceptions is considered more Pythonic (not bare excepts though) so something that has a chance of handling it can see it and possibly deal with it. – Jon Clements May 21 '17 at 12:47

1 Answers1

0

I can't speak to whether something is Pythonic but I can speak to why it leads to more concise code. In general you're doing a lot of things, not just looking at one index. So consider what happens when I'm looking at several attributes in a dictionary:

try:
    obj.a = data['a']
    obj.b = data['b']
    obj.c = data['c']
except KeyError: 
    #Oops our data didn't have all we needed.

Each of those assignments would have needed to be an if statement without using the exception handling. That is, the more things you can do in an try block, the less percentage of your overall code will need to deal with errors.

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
Sam Hartman
  • 6,210
  • 3
  • 23
  • 40
  • What is the advantage of scaling up exceptions? – overexchange May 21 '17 at 12:44
  • @overexchange Corrected answer. It's not so much that exceptions scale up is that your code is more efficient when you can share the same error handler across a lot of tasks. – Sam Hartman May 21 '17 at 12:55
  • 2
    Notice that this is fine as long as you fail *before actually mutating state* (otherwise you have to do your bookkeeping anyway to revert) and if you are sure that the exception you are trapping only comes from the cases you are thinking about. – Matteo Italia May 21 '17 at 13:01
  • 1
    @MatteoItalia which in this specific case you could do with `obj.a, obj.b, obj.c = itemgetter(*'abc')(data)` as it'd let the KeyError handle itself nicely, but could still propagate exceptions depending on the assignment but in more complicated scenarios... yeah... you'd need to do other things... – Jon Clements May 21 '17 at 13:06
  • O, yeah, but talking about how broad a try block can be would be way too broad for this question and would be well into writing a tutorial territory. – Sam Hartman May 21 '17 at 13:18
  • So, hasattr() kind of check should always be avoided before setattr()? As it is not EAFP? – overexchange May 21 '17 at 23:47
  • @overexchange There is no always; there are only tools to use when they are helpful. Use hasattr when it makes your code more maintainable and reduces the chances of errors. Use exceptions when they do the same. Repeating the same code pattern multiple times is a good hint that you can probably do something better. – Sam Hartman May 21 '17 at 23:51