Awsome Python - chained exceptions

Discussion in 'Python' started by Steven D'Aprano, Feb 12, 2013.

  1. As an antidote to the ill-informed negativity of Ranting Rick's
    illusionary "PyWarts", I thought I'd present a few of Python's more
    awesome features, starting with exception contexts.

    If you've ever written an exception handler, you've probably written a
    *buggy* exception handler:


    def getitem(items, index):
    # One-based indexing.
    try:
    return items[index-1]
    except IndexError:
    print ("Item at index %d is missing" % index - 1) # Oops!


    Unfortunately, when an exception occurs inside an except or finally
    block, the second exception masks the first, and the reason for the
    original exception is lost:

    py> getitem(['one', 'two', 'three'], 5) # Python 2.6
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 6, in getitem
    TypeError: unsupported operand type(s) for -: 'str' and 'int'


    But never fear! In Python 3.1 and better, Python now shows you the full
    chain of multiple exceptions, and exceptions grow two new special
    attributes: __cause__ and __context__.

    If an exception occurs while handling another exception, Python sets the
    exception's __context__ and displays an extended error message:


    py> getitem(['one', 'two', 'three'], 5) # Python 3.1
    Traceback (most recent call last):
    File "<stdin>", line 4, in getitem
    IndexError: list index out of range

    During handling of the above exception, another exception occurred:

    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 6, in getitem
    TypeError: unsupported operand type(s) for -: 'str' and 'int'



    Python 3 also allows you to explicitly set the exception's __cause__
    using "raise...from" syntax:

    py> try:
    .... len(None)
    .... except TypeError as e:
    .... raise ValueError('bad value') from e
    ....
    Traceback (most recent call last):
    File "<stdin>", line 2, in <module>
    TypeError: object of type 'NoneType' has no len()

    The above exception was the direct cause of the following exception:

    Traceback (most recent call last):
    File "<stdin>", line 4, in <module>
    ValueError: bad value



    Note the slight difference in error message. If both __cause__ and
    __context__ are set, the __cause__ takes priority.


    Sometimes you actually want to deliberately catch one exception and raise
    another, without showing the first exception. A very common idiom in
    Python 2:


    try:
    do_work()
    except SomeInternalError:
    raise PublicError(error_message)


    Starting with Python 3.3, there is now support from intentionally
    suppressing the __context__:


    py> try:
    .... len(None)
    .... except TypeError:
    .... raise ValueError('bad value') from None # Python 3.3
    ....
    Traceback (most recent call last):
    File "<stdin>", line 4, in <module>
    ValueError: bad value



    You can read more about exception chaining here:

    http://www.python.org/dev/peps/pep-3134/
    http://www.python.org/dev/peps/pep-0409/



    --
    Steven
     
    Steven D'Aprano, Feb 12, 2013
    #1
    1. Advertising

  2. Steven D'Aprano

    Terry Reedy Guest

    On 2/12/2013 1:15 AM, Steven D'Aprano wrote:
    > As an antidote to the ill-informed negativity of Ranting Rick's
    > illusionary "PyWarts", I thought I'd present a few of Python's more
    > awesome features, starting with exception contexts.


    You do not need Rick to justify such an informative post.

    > If you've ever written an exception handler, you've probably written a
    > *buggy* exception handler:
    >
    >
    > def getitem(items, index):
    > # One-based indexing.
    > try:
    > return items[index-1]
    > except IndexError:
    > print ("Item at index %d is missing" % index - 1) # Oops!
    >
    >
    > Unfortunately, when an exception occurs inside an except or finally
    > block, the second exception masks the first, and the reason for the
    > original exception is lost:
    >
    > py> getitem(['one', 'two', 'three'], 5) # Python 2.6
    > Traceback (most recent call last):
    > File "<stdin>", line 1, in <module>
    > File "<stdin>", line 6, in getitem
    > TypeError: unsupported operand type(s) for -: 'str' and 'int'
    >
    >
    > But never fear! In Python 3.1 and better, Python now shows you the full
    > chain of multiple exceptions, and exceptions grow two new special
    > attributes: __cause__ and __context__.


    Some thought was given to having only one special attribute, but in the
    end it was decided to have __context__ be the actual context and
    __cause__ be the programmer set and displayed 'context'.

    > If an exception occurs while handling another exception, Python sets the
    > exception's __context__ and displays an extended error message:
    >
    > py> getitem(['one', 'two', 'three'], 5) # Python 3.1
    > Traceback (most recent call last):
    > File "<stdin>", line 4, in getitem
    > IndexError: list index out of range
    >
    > During handling of the above exception, another exception occurred:
    >
    > Traceback (most recent call last):
    > File "<stdin>", line 1, in <module>
    > File "<stdin>", line 6, in getitem
    > TypeError: unsupported operand type(s) for -: 'str' and 'int'
    >
    > Python 3 also allows you to explicitly set the exception's __cause__
    > using "raise...from" syntax:
    >
    > py> try:
    > ... len(None)
    > ... except TypeError as e:
    > ... raise ValueError('bad value') from e
    > ...
    > Traceback (most recent call last):
    > File "<stdin>", line 2, in <module>
    > TypeError: object of type 'NoneType' has no len()
    >
    > The above exception was the direct cause of the following exception:
    >
    > Traceback (most recent call last):
    > File "<stdin>", line 4, in <module>
    > ValueError: bad value
    >
    > Note the slight difference in error message. If both __cause__ and
    > __context__ are set, the __cause__ takes priority.
    >
    > Sometimes you actually want to deliberately catch one exception and raise
    > another, without showing the first exception. A very common idiom in
    > Python 2:
    >
    > try:
    > do_work()
    > except SomeInternalError:
    > raise PublicError(error_message)
    >
    > Starting with Python 3.3, there is now support from intentionally
    > suppressing the __context__:
    >
    > py> try:
    > ... len(None)
    > ... except TypeError:
    > ... raise ValueError('bad value') from None # Python 3.3
    > ...
    > Traceback (most recent call last):
    > File "<stdin>", line 4, in <module>
    > ValueError: bad value
    >

    The new features are explained in the Library manual, Ch. 5, Exceptions,
    but without so many clear examples. The 'from None' option has not yet
    been added to the Language reference section on raise statements (an
    issue on the tracker), so it is easy to miss if one does not also read
    the Library chapter.
    >
    > You can read more about exception chaining here:
    >
    > http://www.python.org/dev/peps/pep-3134/
    > http://www.python.org/dev/peps/pep-0409/


    --
    Terry Jan Reedy
     
    Terry Reedy, Feb 12, 2013
    #2
    1. Advertising

  3. Steven D'Aprano

    Zero Piraeus Guest

    :

    On 12 February 2013 02:15, Steven D'Aprano
    <> wrote:
    > As an antidote to the ill-informed negativity of Ranting Rick's
    > illusionary "PyWarts", I thought I'd present a few of Python's more
    > awesome features [...]


    You could call them PyW00ts.

    -[]z.
     
    Zero Piraeus, Feb 12, 2013
    #3
  4. Steven D'Aprano

    Ethan Furman Guest

    On 02/12/2013 10:01 AM, Zero Piraeus wrote:
    > On 12 February 2013 02:15, Steven D'Aprano wrote:
    >> As an antidote to the ill-informed negativity of Ranting Rick's
    >> illusionary "PyWarts", I thought I'd present a few of Python's more
    >> awesome features [...]

    >
    > You could call them PyW00ts.


    +1 QOTW
     
    Ethan Furman, Feb 12, 2013
    #4
  5. Steven D'Aprano

    Rick Johnson Guest

    On Tuesday, February 12, 2013 12:15:29 AM UTC-6, Steven D'Aprano wrote:
    > [snip inflammatory remarks]
    > I thought I'd present a few of Python's more
    > awesome features, starting with exception contexts.


    Well that's great idea, however, in order to find this very "valuable" information the searcher must not only remember an unintuitive search tag, he must also remember /exactly/ how you misspelled the unintuitive search tag! I sure hope you have more of these "Awsome Python"'s to share because i fear this one will surely be forgotten in 2 days.

    > If you've ever written an exception handler, you've probably written a
    > *buggy* exception handler:
    >
    > def getitem(items, index):
    > # One-based indexing.
    > try:
    > return items[index-1]
    > except IndexError:
    > print ("Item at index %d is missing" % index - 1) # Oops!
    >
    >
    > Unfortunately, when an exception occurs inside an except or finally
    > block, the second exception masks the first, and the reason for the
    > original exception is lost:
    >
    > py> getitem(['one', 'two', 'three'], 5) # Python 2.6
    > Traceback (most recent call last):
    > File "<stdin>", line 1, in <module>
    > File "<stdin>", line 6, in getitem
    > TypeError: unsupported operand type(s) for -: 'str' and 'int'


    But that's exactly what any sane person wants to happen. And i don't know why your error messages are so vague because i got this message (using IDLE):

    py> getitem([1,2,3], 5)
    Traceback (most recent call last):
    File "<pyshell#3>", line 1, in <module>
    getitem([1,2,3], 5)
    File "<pyshell#1>", line 5, in getitem
    print ("Item at index %d is missing" % index - 1) # Oops!
    TypeError: unsupported operand type(s) for -: 'str' and 'int'

    Which (by showing the offensive line) is quite clear to me. I even tried a simplified version on the command line (to make sure IDLE was not injectinganything) and got a better exception message, but sadly without the offending line:

    py> try:
    .... l[10]
    .... except IndexError:
    .... "{0}".format(blah)
    ....
    Traceback (most recent call last):
    File "<stdin>", line 4, in <module>
    NameError: name 'blah' is not defined

    But in either case, both forms of the message i got are far more helpful than the exception you posted. Did you trim the exception in an attempt to sensationalize the problem?

    But who cares about the exception message python returned when there are /so/ many abominations in this code sample. I mean, i know this is an example, but it should not be an example of "how not to code"+"ANYTHING"+"!"*10

    Some of the problems include:

    1. You are using the print function (so we can assume you are using Python 3.x) but then you go and use that old ugly "%" string interpolation syntax crap! when you should have used the format method of strings.

    print("Item at index {0} is missing".format(index-1)) # Oops!

    ....Oh Steven, if you only knew how we interpreted the "Oops!", more like "Doh!".

    2. Your stdout message is not only confusing, it's a freaking lie!

    "Item at index %d is missing".

    ....Steven, i can assure you that if "list[index]" raises an IndexError, theitem is NOT /missing/. Neither the item OR the index even /exist/ as far as the sequence is concerned. Contrary to your naive beliefs, Python sequences are not initialized with every possible integer index (that the current machine can represent) just sitting around twiddling their thumbs complaining of boredom whilst waiting for a value to come along they can point to; can you imagine the memory usage of such a design (flaw)?

    3. Your claim that the broken code in the "exception block" masks the exception that would have been raised by the code in the "try block" is false, because if it's true, then you'd better find the fool who told Python to mask the try block in the first place!

    Got any more bright ideas DeAprano? (Oh gawd that felt good!)
     
    Rick Johnson, Feb 13, 2013
    #5
  6. Steven D'Aprano

    Rick Johnson Guest

    On Tuesday, February 12, 2013 12:01:45 PM UTC-6, Zero Piraeus wrote:

    > You could call them PyW00ts.


    +1 on the name
    -INFINITY on the execution

    Actually i am happy that DeAprano used the unintuitive tag now. Bad enough to use an unintuitive tag. Worse to misspell it. But it would been a crime to tarnish such an intuitive tag as "PyW00ts" with the clumsy teachings provided.
     
    Rick Johnson, Feb 13, 2013
    #6
  7. Steven D'Aprano

    Rick Johnson Guest

    On Tuesday, February 12, 2013 12:01:45 PM UTC-6, Zero Piraeus wrote:

    > You could call them PyW00ts.


    +1 on the name
    -INFINITY on the execution

    Actually i am happy that DeAprano used the unintuitive tag now. Bad enough to use an unintuitive tag. Worse to misspell it. But it would been a crime to tarnish such an intuitive tag as "PyW00ts" with the clumsy teachings provided.
     
    Rick Johnson, Feb 13, 2013
    #7
  8. On Wed, Feb 13, 2013 at 1:47 PM, Rick Johnson
    <> wrote:
    >On Tuesday, February 12, 2013 12:15:29 AM UTC-6, Steven D'Aprano wrote:
    >> If you've ever written an exception handler, you've probably written a
    >> *buggy* exception handler:
    >>
    >> def getitem(items, index):
    >> # One-based indexing.
    >> try:
    >> return items[index-1]
    >> except IndexError:
    >> print ("Item at index %d is missing" % index - 1) # Oops!
    >>
    >>
    >> Unfortunately, when an exception occurs inside an except or finally
    >> block, the second exception masks the first, and the reason for the
    >> original exception is lost:
    >>
    >> py> getitem(['one', 'two', 'three'], 5) # Python 2.6
    >> Traceback (most recent call last):
    >> File "<stdin>", line 1, in <module>
    >> File "<stdin>", line 6, in getitem
    >> TypeError: unsupported operand type(s) for -: 'str' and 'int'

    >
    > Which (by showing the offensive line) is quite clear to me.


    No, the offending (not offensive) line is "return items[index-1]",
    which doesn't feature in your traceback at all. It DOES, however,
    feature in the Py3.1 double traceback (it's listed as line 4)..

    > 1. You are using the print function (so we can assume you are using Python 3.x)


    He is? Could just as easily be the print statement with a single
    argument, with unnecessary parentheses around that argument. Which, if
    I recall correctly, is one of the recommended approaches for making
    2/3 bi-compatible code.

    > but then you go and use that old ugly "%" string interpolation syntax crap! when you should have used the format method of strings.
    >
    > print("Item at index {0} is missing".format(index-1)) # Oops!
    >
    > ...Oh Steven, if you only knew how we interpreted the "Oops!", more like "Doh!".


    No. Definitely not. Percent interpolation isn't going anywhere - core
    devs have said so - and there are many occasions when it is at least
    as well suited to the task as .format() is. Also, it's a notation
    that's well understood *across languages* and in a variety of message
    interpolation systems. Anyone who's worked with *any* of them will
    understand that %s inserts a string, %d a number (in decimal), etc,
    etc. Granted, the exact details after that may change (eg Python has
    %r to emit the representation, while Pike uses %O for "any object",
    with similar notation), but the format specifiers and modifiers that
    came from C are fairly stable, readable, and compact.

    In what way is a trivial example like this improved by the use of
    format()? The ONLY thing I can think of is that, by forcing you to put
    parentheses around the argument, it avoids the issue from the original
    post, which is one of operator precedence - but that's something
    that's fairly easy to spot when you know what you're looking for, and
    is definitely not specific to string formatting.

    ChrisA
     
    Chris Angelico, Feb 13, 2013
    #8
  9. On Feb 13, 2013 12:00 AM, "Chris Angelico" <> wrote:

    > Which word? "we"? I'm not entirely sure, given that non-monospaced
    > fonts get in the way. Normally people would put exactly as many >

    carets/tildes as there are letters in the word, but aligning the text
    > in a mono font puts the carets under "we", so that clue isn't there.


    Sorry I assumed that on a technical list like this one folks would be
    viewing emails as the internet gods intended, in a nice monospace font.

    I don't see how leading carets would help in a proportional font; it just
    doesn't work well for quoting emails I think. Maybe that's why email from
    html clients seem to do a lot of top posting and ditch quoting (and I fear
    reading) emails all together.

    Apologies if the quoted stuff is messed up in this email. Darn phones are
    not good at doing proper emailing.
     
    Michael Torrie, Feb 13, 2013
    #9
  10. Steven D'Aprano

    Rick Johnson Guest

    On Wednesday, February 13, 2013 12:58:46 AM UTC-6, Chris Angelico wrote:
    > On Wed, Feb 13, 2013 at 1:47 PM, Rick Johnson wrote:
    > >On Tuesday, February 12, 2013 12:15:29 AM UTC-6, Steven D'Aprano wrote:
    > >> If you've ever written an exception handler, you've probably written a
    > >> *buggy* exception handler:
    > >>
    > >> def getitem(items, index):
    > >> # One-based indexing.
    > >> try:
    > >> return items[index-1]
    > >> except IndexError:
    > >> print ("Item at index %d is missing" % index - 1) # Oops!
    > >>
    > >>
    > >> Unfortunately, when an exception occurs inside an except or finally
    > >> block, the second exception masks the first, and the reason for the
    > >> original exception is lost:
    > >>
    > >> py> getitem(['one', 'two', 'three'], 5) # Python 2.6
    > >> Traceback (most recent call last):
    > >> File "<stdin>", line 1, in <module>
    > >> File "<stdin>", line 6, in getitem
    > >> TypeError: unsupported operand type(s) for -: 'str' and 'int'

    > >
    > > Which (by showing the offensive line) is quite clear to me.

    >
    > No, the offending (not offensive) line is "return items[index-1]",
    > which doesn't feature in your traceback at all.


    Do you realize that you are quoting DeAprano and not me? Whether you realize this fact or not, consider the next two questions.

    Q1: How could a line in the "try" block ever be considered
    offensive? Because it throws an error? Are you serious?

    Q2: Why would the line in the try block be shown as
    a "feature" of the traceback when the whole intent of
    exception handling is to hide the error in the try
    block! If you want to raise the exception in the try block
    then you place a naked raise statement in the exception
    block, BUT THEN, why even wrap the code in a try/except
    in the first damn place!?

    Man, you and DeAprano must be cut from the same block; or more correctly, carved by the same shaky hand of a creator suffering the late-stage effects of Alzheimers disease.

    > It DOES, however,
    > feature in the Py3.1 double traceback (it's listed as line 4)..
    >
    > > 1. You are using the print function (so we can assume you are using Python 3.x)

    >
    > He is? Could just as easily be the print statement with a single
    > argument, with unnecessary parentheses around that argument. Which, if
    > I recall correctly, is one of the recommended approaches for making
    > 2/3 bi-compatible code.


    Really?

    Because if he did in-fact write the print statement using parenthesis (in some foolish attempt to make his code forward-compatible) that would mean i should add /another/ coding abomination to my earlier list of abominations.The proper method of using a forward compatible print function is by /importing/ the feature.

    from future import print_function

    > No. Definitely not. Percent interpolation isn't going anywhere - core
    > devs have said so - and there are many occasions when it is at least
    > as well suited to the task as .format() is.


    In other words: Screw consistency and to hell with the zen?

    > Also, it's a notation
    > that's well understood *across languages* and in a variety of message
    > interpolation systems. Anyone who's worked with *any* of them will
    > understand that %s inserts a string, %d a number (in decimal), etc,


    Oh yes, because indexing the list of arguments in the format method is SO much more overhead! Heck, Python>=2.7 (read the docs for exact release number) will allow you to implicitly pass the index:

    print "{} is one more than {}".format("five", "four") # 3.something

    ....is equivalent to:

    print "{0} is one more than {1}".format("five", "four")

    ....but what about when you need to substitute the /same/ substring in more than one location? Using the old nasty interpolation you are foced to writethis:

    print "Chris is a %s who is very %s-ish"%('troll', 'troll')

    ....ewwww yuck! String.format() to the rescue!

    print "Chris is a {0} who is very {0}-ish".format('troll')

    In fact all of these posted examples work in Python>=2.7.

    So the moral is: You can pass no indexes and the format method will intuit the indexes from their linear position in the string, or you can pass indexes and be explicit (plus you can reference a value more than once!), or youcan choose one of the many other great options available of the format method.

    http://docs.python.org/2/library/string.html#format-string-syntax

    > etc. Granted, the exact details after that may change (eg Python has
    > %r to emit the representation, while Pike uses %O for "any object",
    > with similar notation), but the format specifiers and modifiers that
    > came from C are fairly stable, readable, and compact.


    The fact is that "str.format(args)" beats the pants off string interpolation any day and anybody arguing for keeping string interpolation is not thinking clearly (especially when they first claim consistency between languagesand them expose that claim as a lie) and is also anti-pythonic! To continue to propagate foolish language designs simply because other people have been brainwashed by them is, well, foolish. Would you propagate propaganda using the same excuse?

    > In what way is a trivial example like this improved by the use of
    > format()? The ONLY thing I can think of is that, by forcing you to put
    > parentheses around the argument,


    You think the only difference between string.format() and string interpolation is parenthesis? Chris, just because you don't understand how to use str..format() (or interpolation!) correctly does not mean other python programmers are unable too.

    > it avoids the issue from the original
    > post, which is one of operator precedence - but that's something
    > that's fairly easy to spot when you know what you're looking for, and
    > is definitely not specific to string formatting.


    So as you say: str.format() solves a bug in the code, but that is not enough excuse to stop using the old cryptic and bug inducing interpolation syntax. I see[1].

    [1] Read as: "I see that you are a lost cause". Hopefully you will grow a brain and read the format docs, and then try to apply it in your code, then MAYBE you will understand why i support str.format as the only method to format a string.

    PS: Why do keep posting email addresses on the list? Does your client not trim, or at least warn, about these?
     
    Rick Johnson, Feb 13, 2013
    #10
  11. Steven D'Aprano

    Rick Johnson Guest

    On Wednesday, February 13, 2013 12:58:46 AM UTC-6, Chris Angelico wrote:
    > On Wed, Feb 13, 2013 at 1:47 PM, Rick Johnson wrote:
    > >On Tuesday, February 12, 2013 12:15:29 AM UTC-6, Steven D'Aprano wrote:
    > >> If you've ever written an exception handler, you've probably written a
    > >> *buggy* exception handler:
    > >>
    > >> def getitem(items, index):
    > >> # One-based indexing.
    > >> try:
    > >> return items[index-1]
    > >> except IndexError:
    > >> print ("Item at index %d is missing" % index - 1) # Oops!
    > >>
    > >>
    > >> Unfortunately, when an exception occurs inside an except or finally
    > >> block, the second exception masks the first, and the reason for the
    > >> original exception is lost:
    > >>
    > >> py> getitem(['one', 'two', 'three'], 5) # Python 2.6
    > >> Traceback (most recent call last):
    > >> File "<stdin>", line 1, in <module>
    > >> File "<stdin>", line 6, in getitem
    > >> TypeError: unsupported operand type(s) for -: 'str' and 'int'

    > >
    > > Which (by showing the offensive line) is quite clear to me.

    >
    > No, the offending (not offensive) line is "return items[index-1]",
    > which doesn't feature in your traceback at all.


    Do you realize that you are quoting DeAprano and not me? Whether you realize this fact or not, consider the next two questions.

    Q1: How could a line in the "try" block ever be considered
    offensive? Because it throws an error? Are you serious?

    Q2: Why would the line in the try block be shown as
    a "feature" of the traceback when the whole intent of
    exception handling is to hide the error in the try
    block! If you want to raise the exception in the try block
    then you place a naked raise statement in the exception
    block, BUT THEN, why even wrap the code in a try/except
    in the first damn place!?

    Man, you and DeAprano must be cut from the same block; or more correctly, carved by the same shaky hand of a creator suffering the late-stage effects of Alzheimers disease.

    > It DOES, however,
    > feature in the Py3.1 double traceback (it's listed as line 4)..
    >
    > > 1. You are using the print function (so we can assume you are using Python 3.x)

    >
    > He is? Could just as easily be the print statement with a single
    > argument, with unnecessary parentheses around that argument. Which, if
    > I recall correctly, is one of the recommended approaches for making
    > 2/3 bi-compatible code.


    Really?

    Because if he did in-fact write the print statement using parenthesis (in some foolish attempt to make his code forward-compatible) that would mean i should add /another/ coding abomination to my earlier list of abominations.The proper method of using a forward compatible print function is by /importing/ the feature.

    from future import print_function

    > No. Definitely not. Percent interpolation isn't going anywhere - core
    > devs have said so - and there are many occasions when it is at least
    > as well suited to the task as .format() is.


    In other words: Screw consistency and to hell with the zen?

    > Also, it's a notation
    > that's well understood *across languages* and in a variety of message
    > interpolation systems. Anyone who's worked with *any* of them will
    > understand that %s inserts a string, %d a number (in decimal), etc,


    Oh yes, because indexing the list of arguments in the format method is SO much more overhead! Heck, Python>=2.7 (read the docs for exact release number) will allow you to implicitly pass the index:

    print "{} is one more than {}".format("five", "four") # 3.something

    ....is equivalent to:

    print "{0} is one more than {1}".format("five", "four")

    ....but what about when you need to substitute the /same/ substring in more than one location? Using the old nasty interpolation you are foced to writethis:

    print "Chris is a %s who is very %s-ish"%('troll', 'troll')

    ....ewwww yuck! String.format() to the rescue!

    print "Chris is a {0} who is very {0}-ish".format('troll')

    In fact all of these posted examples work in Python>=2.7.

    So the moral is: You can pass no indexes and the format method will intuit the indexes from their linear position in the string, or you can pass indexes and be explicit (plus you can reference a value more than once!), or youcan choose one of the many other great options available of the format method.

    http://docs.python.org/2/library/string.html#format-string-syntax

    > etc. Granted, the exact details after that may change (eg Python has
    > %r to emit the representation, while Pike uses %O for "any object",
    > with similar notation), but the format specifiers and modifiers that
    > came from C are fairly stable, readable, and compact.


    The fact is that "str.format(args)" beats the pants off string interpolation any day and anybody arguing for keeping string interpolation is not thinking clearly (especially when they first claim consistency between languagesand them expose that claim as a lie) and is also anti-pythonic! To continue to propagate foolish language designs simply because other people have been brainwashed by them is, well, foolish. Would you propagate propaganda using the same excuse?

    > In what way is a trivial example like this improved by the use of
    > format()? The ONLY thing I can think of is that, by forcing you to put
    > parentheses around the argument,


    You think the only difference between string.format() and string interpolation is parenthesis? Chris, just because you don't understand how to use str..format() (or interpolation!) correctly does not mean other python programmers are unable too.

    > it avoids the issue from the original
    > post, which is one of operator precedence - but that's something
    > that's fairly easy to spot when you know what you're looking for, and
    > is definitely not specific to string formatting.


    So as you say: str.format() solves a bug in the code, but that is not enough excuse to stop using the old cryptic and bug inducing interpolation syntax. I see[1].

    [1] Read as: "I see that you are a lost cause". Hopefully you will grow a brain and read the format docs, and then try to apply it in your code, then MAYBE you will understand why i support str.format as the only method to format a string.

    PS: Why do keep posting email addresses on the list? Does your client not trim, or at least warn, about these?
     
    Rick Johnson, Feb 13, 2013
    #11
  12. Steven D'Aprano

    Rick Johnson Guest

    On Wednesday, February 13, 2013 10:14:34 AM UTC-6, Rick Johnson wrote:
    > The proper method of using a forward compatible print
    > function is by /importing/ the feature.
    >
    > from future import print_function


    Urm... of course the proper /PROPER/ way would be to NOT throw an import error!

    from __future__ import print_function

    O:)
     
    Rick Johnson, Feb 13, 2013
    #12
  13. Steven D'Aprano

    Rick Johnson Guest

    On Wednesday, February 13, 2013 10:14:34 AM UTC-6, Rick Johnson wrote:
    > The proper method of using a forward compatible print
    > function is by /importing/ the feature.
    >
    > from future import print_function


    Urm... of course the proper /PROPER/ way would be to NOT throw an import error!

    from __future__ import print_function

    O:)
     
    Rick Johnson, Feb 13, 2013
    #13
  14. On Thu, Feb 14, 2013 at 3:14 AM, Rick Johnson
    <> wrote:
    > On Wednesday, February 13, 2013 12:58:46 AM UTC-6, Chris Angelico wrote:
    >> No, the offending (not offensive) line is "return items[index-1]",
    >> which doesn't feature in your traceback at all.

    >
    > Do you realize that you are quoting DeAprano and not me? Whether you realize this fact or not, consider the next two questions.


    I knew who I was quoting.

    > Q1: How could a line in the "try" block ever be considered
    > offensive? Because it throws an error? Are you serious?


    You're the one who said offensive. I specifically corrected you to
    "offending", which is the appropriate word in that situation.

    > Q2: Why would the line in the try block be shown as
    > a "feature" of the traceback when the whole intent of
    > exception handling is to hide the error in the try
    > block! If you want to raise the exception in the try block
    > then you place a naked raise statement in the exception
    > block, BUT THEN, why even wrap the code in a try/except
    > in the first damn place!?


    You seriously need to get into the real world and do some actual
    debugging work. Here, let me give you an example of what you might
    come across in the real world:

    1) The program doesn't exhibit the failure symptoms until it's been
    running for a couple of days.
    2) Sending the program a SIGHUP influences the symptoms in peculiar ways.
    3) The main symptom visible is that something that ought to have 2-3
    threads actually has several hundred.
    4) Your boss is paranoid about security, so the script files on the
    running nodes have all been minified - no comments, no linebreaks,
    short variable names, etc.
    5) The exact nature of the bug depends on the interactions of up to 12
    computers, all running similar code but doing different tasks.

    Now tell me, what's the first thing you do? There are many right
    answers to this question, but most of them involve one thing: Get more
    information. Turn on verbose logging, add a monitoring wrapper, insert
    output statements in various places... and make sure your exception
    tracebacks give ALL the information.

    > Man, you and DeAprano must be cut from the same block; or more correctly,carved by the same shaky hand of a creator suffering the late-stage effects of Alzheimers disease.


    D'Aprano (note, that's a 39 not a 101) and I both happen to have some
    real-world experience. A bit of a rough teacher, and the tuition fees
    are ridiculously high, but you learn things that aren't taught
    anywhere else.

    >> He is? Could just as easily be the print statement with a single
    >> argument, with unnecessary parentheses around that argument. Which, if
    >> I recall correctly, is one of the recommended approaches for making
    >> 2/3 bi-compatible code.

    >
    > Really?
    >
    > Because if he did in-fact write the print statement using parenthesis (insome foolish attempt to make his code forward-compatible) that would mean i should add /another/ coding abomination to my earlier list of abominations. The proper method of using a forward compatible print function is by /importing/ the feature.
    >
    > from future import print_function


    >>> import __future__
    >>> __future__.print_function

    _Feature((2, 6, 0, 'alpha', 2), (3, 0, 0, 'alpha', 0), 65536)

    Which works back as far as 2.6 but that's all. Simply putting parens
    around the argument works all the way back to... hmm. Further back
    than I've ever had to support, but then, I only started using Python
    seriously a few years ago. Steven?

    >> No. Definitely not. Percent interpolation isn't going anywhere - core
    >> devs have said so - and there are many occasions when it is at least
    >> as well suited to the task as .format() is.

    >
    > In other words: Screw consistency and to hell with the zen?


    Percent interpolation is plenty obvious, it's simple, it's clean, and
    you're welcome to hate it if you like. Doesn't bother me.

    > ...but what about when you need to substitute the /same/ substring in more than one location? Using the old nasty interpolation you are foced to write this:
    >
    > print "Chris is a %s who is very %s-ish"%('troll', 'troll')
    >
    > ...ewwww yuck! String.format() to the rescue!
    >
    > print "Chris is a {0} who is very {0}-ish".format('troll')


    Yeah, in Pike I'd just use %<s to reuse the argument, or %[0]s to
    explicitly set the index. If Python didn't have .format() and the
    percent-haters like you, those features could easily be implemented.
    If all you're doing is concatenating five strings, three of them
    constants, there are plenty of other ways to do it; are you going to
    start hating on str.format because you could use concatenation or
    str.join()? Which is the one obvious way to do it?

    So let's look at a more useful example. You need to tabulate some
    data. For each line of output, you have a descriptive string, a
    number, and a floating point value, and you want to output them like
    this:

    Normal 73 105.23
    Disconnected 32 14.00
    Shutting down 0 0.00
    Busy 3 1333.33
    Overloaded 1 1942.07

    Your input is a list of lists or tuples with those three types: str,
    int, float. You need to format them. Code golf mode, or maximum
    clarity mode, up to you. Here are my options:

    # Python, str.format()
    for row in data:
    print("{:15s}{:4d}{:11.2f}".format(*row))

    # Python, percent-formatting
    for row in data:
    print("%-15s%4d%11.2f"%row)

    //C++ - using a struct rather than a mixed array
    for (record *row=data;row->desc;++row)
    printf("%-15s%4d%11.2f\n",row->desc,row->count,row->load);

    //Pike, direct translation
    foreach (data,array row)
    write("%-15s%4d%11.2f\n",@row);

    //Pike, making use of array-output feature
    write("%{%-15s%4d%11.2f\n%}",data);

    Note how easily tabulated data can be produced, *across languages*,
    with the exact same syntax. Actually, str.format borrows heavily from
    printf notation, and I was able to make it look almost the same; all
    it does is replace the percent sign with {:}. (Oh, and it defaults to
    left-justifying strings, so I don't need the minus sign to do that.
    Big deal.)

    > (especially when they first claim consistency between languages and them expose that claim as a lie)


    I think the comparison above shows my claim to be not a lie.

    > [1] Read as: "I see that you are a lost cause". Hopefully you will grow abrain and read the format docs, and then try to apply it in your code, then MAYBE you will understand why i support str.format as the only method to format a string.


    I've been working on that whole "growing a brain" thing, and I've
    pretty much mastered it. My last troll almost grew one before he
    committed suicide in shame. Would you like me to try the technique on
    your body? It has a 90% chance of success.

    > PS: Why do keep posting email addresses on the list? Does your client nottrim, or at least warn, about these?


    They're in the headers. What's the big deal? This is an email mailing
    list, not just a newsgroup.

    ChrisA
     
    Chris Angelico, Feb 13, 2013
    #14
  15. On Thu, 14 Feb 2013 09:10:42 +1100, Chris Angelico wrote:

    Quoting Rick Johnson:
    >> Q2: Why would the line in the try block be shown as a "feature" of
    >> the traceback when the whole intent of exception handling is to hide
    >> the error in the try block! If you want to raise the exception in the
    >> try block then you place a naked raise statement in the exception
    >> block, BUT THEN, why even wrap the code in a try/except in the first
    >> damn place!?


    Here is one example of using raise to re-raise an exception you have just
    caught:

    import errno
    paths = ["here", "there", "somewhere else"]
    for location in paths:
    filename = os.path.join(location, "prefs.ini")
    try:
    f = open(filename)
    except IOError as e:
    if e.errno != errno.ENOENT: # File not found.
    raise


    > You seriously need to get into the real world and do some actual
    > debugging work.


    Amen to that brother. What is it that they say?

    "Those who can, do. Those who can't, teach. Those who can't teach, write
    rants on the Internet criticising others."


    [...]
    >>> He is? Could just as easily be the print statement with a single
    >>> argument, with unnecessary parentheses around that argument. Which, if
    >>> I recall correctly, is one of the recommended approaches for making
    >>> 2/3 bi-compatible code.

    >>
    >> Really?
    >>
    >> Because if he did in-fact write the print statement using parenthesis
    >> (in some foolish attempt to make his code forward-compatible) that
    >> would mean i should add /another/ coding abomination to my earlier list
    >> of abominations. The proper method of using a forward compatible print
    >> function is by /importing/ the feature.
    >>
    >> from future import print_function

    >
    >>>> import __future__
    >>>> __future__.print_function

    > _Feature((2, 6, 0, 'alpha', 2), (3, 0, 0, 'alpha', 0), 65536)
    >
    > Which works back as far as 2.6 but that's all. Simply putting parens
    > around the argument works all the way back to... hmm. Further back than
    > I've ever had to support, but then, I only started using Python
    > seriously a few years ago. Steven?


    Putting parens around the argument to print works going back to at least
    Python 0.9.1, which is before Python had "" delimiters:


    steve@runes:~$ ./python0.9.1
    >>> s = "string"

    Parsing error: file <stdin>, line 1:
    s = "string"
    ^
    Unhandled exception: run-time error: syntax error
    >>> s = 'string'
    >>> print s

    string
    >>> print (s)

    string

    You can always wrap any expression with an extra pair of round brackets.

    Of course, the correct way of doing this is with "from __future__ import
    print_function", but really, who cares? It's just a trivial example. If
    the worst criticism someone can make of my example is that I took a short-
    cut when printing, I can live with that.



    --
    Steven
     
    Steven D'Aprano, Feb 14, 2013
    #15
  16. Steven D'Aprano

    Ian Kelly Guest

    On Tue, Feb 12, 2013 at 8:01 PM, Rick Johnson
    <> wrote:
    > On Tuesday, February 12, 2013 12:01:45 PM UTC-6, Zero Piraeus wrote:
    >
    >> You could call them PyW00ts.

    >
    > +1 on the name
    > -INFINITY on the execution
    >
    > Actually i am happy that DeAprano used the unintuitive tag now. Bad enough to use an unintuitive tag. Worse to misspell it. But it would been a crime to tarnish such an intuitive tag as "PyW00ts" with the clumsy teachings provided.


    1. Subject lines are not tags. If you want to categorize the post
    with a tag for later reference, then by all means do so; any halfway
    decent reader will let you do this. It's not up to the post author to
    tag posts for you.

    2. If you're going to criticize someone for their spelling, at least
    be sure to spell correctly the name of the person you are addressing.
    You've consistently misspelled Steven's surname in several posts that
    I've noticed.
     
    Ian Kelly, Feb 14, 2013
    #16
  17. Am 13.02.2013 um 17:14 schrieb Rick Johnson:
    > Q1: How could a line in the "try" block ever be considered
    > offensive? Because it throws an error?


    try:
    rrick.go_and_fuck_yourself()
    finally:
    rrick.get_lost()


    See, wasn't that difficult, was it? :D


    > Are you serious?


    No, I just couldn't resist this invitation even though I'm making a fool
    of myself responding to flamers/trolls...

    *le sigh*

    Uli
     
    Ulrich Eckhardt, Feb 14, 2013
    #17
  18. Steven D'Aprano

    alex23 Guest

    On Feb 14, 5:00 pm, Ian Kelly <> wrote:
    > 2. If you're going to criticize someone for their spelling, at least
    > be sure to spell correctly the name of the person you are addressing.
    > You've consistently misspelled Steven's surname in several posts that
    > I've noticed.


    The correct spelling conflicts with his intuition of how it should be
    spelled. Expect a DeApranoWart post any day now.
     
    alex23, Feb 15, 2013
    #18
  19. Steven D'Aprano

    Rick Johnson Guest

    On Thursday, February 14, 2013 6:01:51 AM UTC-6, Ulrich Eckhardt wrote:
    > [...]
    >
    > try:
    > rrick.go_and_[edit]_yourself()
    > finally:
    > rrick.get_lost()


    Oops, you forgot to catch "FloatingPointError" and so your code choked in the try block -- typical newbie mistake.
     
    Rick Johnson, Feb 15, 2013
    #19
  20. On Fri, Feb 15, 2013 at 1:56 PM, Rick Johnson
    <> wrote:
    > On Thursday, February 14, 2013 6:01:51 AM UTC-6, Ulrich Eckhardt wrote:
    >> [...]
    >>
    >> try:
    >> rrick.go_and_[edit]_yourself()
    >> finally:
    >> rrick.get_lost()

    >
    > Oops, you forgot to catch "FloatingPointError" and so your code choked in the try block -- typical newbie mistake.


    And yet it is still a perfect example of how a line of code inside a
    'try' block can indeed be offensive. This has nothing to do with
    exceptions, and everything to do with societal practices and
    acceptable language. The fact that you edited it out of your quote
    shows just how offensive the expression is. :)

    May I ring your schoolbell?

    ChrisA
     
    Chris Angelico, Feb 15, 2013
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Mike H
    Replies:
    1
    Views:
    705
    Chris Smith
    Feb 27, 2004
  2. Volker Grabsch

    Multiple "cmp"s chained one after another

    Volker Grabsch, May 14, 2005, in forum: Python
    Replies:
    11
    Views:
    510
    Glauco Silva
    May 16, 2005
  3. Marcin Ciura
    Replies:
    27
    Views:
    586
    Terry Reedy
    Mar 22, 2007
  4. Rowland Smith

    chained exceptions

    Rowland Smith, Jun 10, 2008, in forum: Python
    Replies:
    0
    Views:
    297
    Rowland Smith
    Jun 10, 2008
  5. Ivan Fomichev

    Chained exceptions in Perl

    Ivan Fomichev, May 4, 2007, in forum: Perl Misc
    Replies:
    0
    Views:
    96
    Ivan Fomichev
    May 4, 2007
Loading...

Share This Page