which is more 'pythonic' / 'better' ?

Discussion in 'Python' started by gabor, Sep 12, 2005.

  1. gabor

    gabor Guest

    hi,

    there are 2 versions of a simple code.
    which is preferred?


    ===
    if len(line) >= (n+1):
    text = line[n]
    else:
    text = 'nothing'
    ===


    ===
    try:
    text = line[n]
    except IndexError:
    text = 'nothing'
    ===


    which is the one you would use?

    thanks,
    gabor
    gabor, Sep 12, 2005
    #1
    1. Advertising

  2. gabor

    Will McGugan Guest

    gabor wrote:
    > hi,
    >
    > there are 2 versions of a simple code.
    > which is preferred?
    >
    >
    > ===
    > if len(line) >= (n+1):
    > text = line[n]
    > else:
    > text = 'nothing'
    > ===
    >
    >
    > ===
    > try:
    > text = line[n]
    > except IndexError:
    > text = 'nothing'
    > ===
    >
    >
    > which is the one you would use?


    I would actualy use the following for this particular case..

    text = line[n:n+1] or 'nothing'

    But in general I think it is best to use exceptions like that only where
    you expect the code to _not_ throw the exception the majority of
    times. Otherwise the simple condition is better. Although I expect there
    is not much difference either way..


    Will McGugan
    --
    http://www.kelpiesoft.com
    Will McGugan, Sep 12, 2005
    #2
    1. Advertising

  3. On Mon, 12 Sep 2005 12:52:52 +0200, gabor wrote:

    > hi,
    >
    > there are 2 versions of a simple code.
    > which is preferred?
    >
    >
    > ===
    > if len(line) >= (n+1):
    > text = line[n]
    > else:
    > text = 'nothing'
    > ===
    >
    >
    > ===
    > try:
    > text = line[n]
    > except IndexError:
    > text = 'nothing'
    > ===
    >
    >
    > which is the one you would use?


    Personally, I would use either. You say po-ta-to, I say pot-at-o.

    try...except... blocks are quick to set up, but slow to catch the
    exception. If you expect that most of your attempts will succeed, then the
    try block will usually be faster than testing the length of the list
    each time.

    But if you expect that the attempts to write the line will fail more
    frequently, then testing will be quicker.

    You will need to do your own testing before hand to find the exact
    cut-off, and expect that cut-off to vary according to the Python
    implementation and version. But a rough rule of thumb is, if you expect
    your code to fail more often than succeed, then test first, otherwise
    catch an exception.



    --
    Steven.
    Steven D'Aprano, Sep 12, 2005
    #3
  4. Will McGugan a écrit :
    > gabor wrote:
    >
    >> hi,
    >>
    >> there are 2 versions of a simple code.
    >> which is preferred?
    >>
    >>
    >> ===
    >> if len(line) >= (n+1):
    >> text = line[n]
    >> else:
    >> text = 'nothing'
    >> ===
    >>
    >>
    >> ===
    >> try:
    >> text = line[n]
    >> except IndexError:
    >> text = 'nothing'
    >> ===
    >>
    >>
    >> which is the one you would use?

    >
    >
    > I would actualy use the following for this particular case..
    >
    > text = line[n:n+1] or 'nothing'


    .... and you would get either a list of one element or a string ...
    I think you wanted to write :

    text = (line[n:n+1] or ['nothing'])[0]

    However, I wouldn't use that because it is hard to read ... you have to
    know Python in great detail to know that:

    1 - is the expressions "line[i:j]", i and j are replaced with
    "len(line)" if they are greater than "len(line)"
    2 - so if n > len(line), then line[n:n+1]" == len[len(line):len(line)]
    == []
    (it is not evident that line[n:n+1] can give an empty list ...)
    3 - empty list evaluate to "False"
    4 - the "or" operator returns the first argument evaluating to "true"

    So, in the end, you use 3 side-effects of Python in the same small
    expression ... (1, 2 and 4)

    >
    > But in general I think it is best to use exceptions like that only where
    > you expect the code to _not_ throw the exception the majority of times.
    > Otherwise the simple condition is better. Although I expect there is not
    > much difference either way..
    >
    >
    > Will McGugan
    > --
    > http://www.kelpiesoft.com


    What I would do is the following:
    - if this happen in a loop, I would, if possible, remove any test and
    catch the exception outside the loop !
    - otherwise, I would go for the test, as it is more straitforward to read.

    Pierre
    Pierre Barbier de Reuille, Sep 12, 2005
    #4
  5. gabor

    Will McGugan Guest

    Pierre Barbier de Reuille wrote:

    >>
    >>I would actualy use the following for this particular case..
    >>
    >>text = line[n:n+1] or 'nothing'

    >
    >
    > ... and you would get either a list of one element or a string ...
    > I think you wanted to write :
    >
    > text = (line[n:n+1] or ['nothing'])[0]


    I was assuming that 'line' would be a string, not a list. Seems more
    likely give the name and context.

    Will McGugan
    --
    http://www.kelpiesoft.com
    Will McGugan, Sep 12, 2005
    #5
  6. Steven D'Aprano wrote:
    > try...except... blocks are quick to set up, but slow to catch the
    > exception. If you expect that most of your attempts will succeed, then the
    > try block will usually be faster than testing the length of the list
    > each time.
    >
    > But if you expect that the attempts to write the line will fail more
    > frequently, then testing will be quicker.
    >
    > You will need to do your own testing before hand to find the exact
    > cut-off, and expect that cut-off to vary according to the Python
    > implementation and version. But a rough rule of thumb is, if you expect
    > your code to fail more often than succeed, then test first, otherwise
    > catch an exception.


    FWIW, these are almost exactly my criteria too. Exceptions are for
    "exceptional" conditions, that is, things that you expect to happen
    infrequently[1]. So if I think the code is going to fail frequently, I
    test the condition, but if I think it won't, I use exceptions.

    STeVe

    [1] Note though that what is "infrequent" in Python might be still
    considered "frequent" in other languages. For example, Java's iterators
    check the result of a .hasNext() method before each .next() call, while
    Python's iterators assume the .next() call will succeed, and simply test
    for the "exceptional" condition of a StopIteration exception.
    Steven Bethard, Sep 12, 2005
    #6
  7. gabor

    Steve Holden Guest

    Will McGugan wrote:
    > Pierre Barbier de Reuille wrote:
    >
    >
    >>>I would actualy use the following for this particular case..
    >>>
    >>>text = line[n:n+1] or 'nothing'

    >>
    >>
    >>... and you would get either a list of one element or a string ...
    >>I think you wanted to write :
    >>
    >>text = (line[n:n+1] or ['nothing'])[0]

    >
    >
    > I was assuming that 'line' would be a string, not a list. Seems more
    > likely give the name and context.
    >

    I'd say it's much more likely that line is a list of lines, since it
    seems improbable that absence of a character should cause a value of
    "nothing" to be required.

    so-i-say-po-tay-to-ly y'rs - steve
    --
    Steve Holden +44 150 684 7255 +1 800 494 3119
    Holden Web LLC http://www.holdenweb.com/
    Steve Holden, Sep 12, 2005
    #7
  8. Steven Bethard wrote:

    > Exceptions are for
    > "exceptional" conditions, that is, things that you expect to happen
    > infrequently[1]. So if I think the code is going to fail frequently, I
    > test the condition, but if I think it won't, I use exceptions.


    I think there exceptions (no pun intended) to that rule as well. A
    classic example is writing to a file. Even if you expect this to be
    impossible, it's best to just create it and trap the exception, thereby
    avoiding a race condition.
    --
    Michael Hoffman
    Michael Hoffman, Sep 12, 2005
    #8
  9. gabor

    Will McGugan Guest

    Steve Holden wrote:

    > I'd say it's much more likely that line is a list of lines, since it
    > seems improbable that absence of a character should cause a value of
    > "nothing" to be required.


    You may be right. I always use plural nouns for collections. To me
    'line' would suggest there was just one of them, so I assumed it was string.


    Will McGugan
    --
    http://www.willmcgugan.com
    "".join({'*':'@','^':'.'}.get(c,0) or chr(97+(ord(c)-84)%26) for c in
    "jvyy*jvyyzpthtna^pbz")
    Will McGugan, Sep 12, 2005
    #9
  10. gabor

    Terry Reedy Guest

    "Will McGugan" <> wrote in message
    news:4325a3fe$0$525$...
    > You may be right. I always use plural nouns for collections.


    ditto
    > To me 'line' would suggest there was just one of them,
    > so I assumed it was string.


    I did too.

    for line in file('skljflask.txt',r): # or similar

    is a common idiom posted here many times.

    Terry J. Reedy
    Terry Reedy, Sep 13, 2005
    #10
  11. gabor

    gabor Guest

    Terry Reedy wrote:
    > "Will McGugan" <> wrote in message
    > news:4325a3fe$0$525$...
    >
    >>You may be right. I always use plural nouns for collections.

    >
    >
    > ditto
    >
    >>To me 'line' would suggest there was just one of them,
    >>so I assumed it was string.

    >
    >
    > I did too.
    >


    i'm sorry ;) it was a list of strings...

    the code was something like:

    for line in open('x.y'):
    line = line.split('\t')


    a better naming would be better it seems :)

    gabor
    gabor, Sep 13, 2005
    #11
  12. gabor

    Terry Reedy Guest

    "gabor" <> wrote in message
    news:433d5$4326783e$c32e4536$...
    > i'm sorry ;) it was a list of strings...
    >
    > the code was something like:
    >
    > for line in open('x.y'):
    > line = line.split('\t')
    >
    > a better naming would be better it seems :)


    Like 'fields', for a list of fields ;-?

    Or your question could have either included the code above or simply
    specified what 'line' was. Asking clear questions is a learning process.

    Terry J. Reedy
    Terry Reedy, Sep 13, 2005
    #12
  13. gabor

    Ken Seehart Guest

    Will McGugan wrote:
    > gabor wrote:
    >
    >> hi,
    >>
    >> there are 2 versions of a simple code.
    >> which is preferred?
    >>
    >>
    >> ===
    >> if len(line) >= (n+1):
    >> text = line[n]
    >> else:
    >> text = 'nothing'
    >> ===
    >>
    >>
    >> ===
    >> try:
    >> text = line[n]
    >> except IndexError:
    >> text = 'nothing'
    >> ===
    >>
    >>
    >> which is the one you would use?

    >
    >
    > I would actualy use the following for this particular case..
    >
    > text = line[n:n+1] or 'nothing'
    >
    > But in general I think it is best to use exceptions like that only where
    > you expect the code to _not_ throw the exception the majority of times.
    > Otherwise the simple condition is better. Although I expect there is not
    > much difference either way..
    >
    >
    > Will McGugan
    > --
    > http://www.kelpiesoft.com


    Hey are you a perl programmer? That looks perlish to me. A python
    programmer would never use "or" that way (even though it works). :)

    It's okay, I used to be a perl programmer too. It's nothing to be
    ashamed of. :)

    - Ken
    Ken Seehart, Sep 13, 2005
    #13
  14. gabor

    Peter Hansen Guest

    Ken Seehart wrote:
    > Will McGugan wrote:
    >> I would actualy use the following for this particular case..
    >>
    >> text = line[n:n+1] or 'nothing'


    > Hey are you a perl programmer? That looks perlish to me. A python
    > programmer would never use "or" that way (even though it works). :)


    I don't think that's at all true. The pattern "somevalue or default" is
    an accepted idiom for returning a default value when "somevalue" is
    False, often used inside __init__ methods to set up attributes. A most
    common case is like this (inside a class obviously):

    def meth(self, things=None):
    self.things = things or []

    (The reason you don't just use a keyword argument of "things=[]" should
    be obvious to all but newbies, and they'll learn a lot by researching
    why so I won't say here. ;-) )

    The alternative is fine too, but insisting on it would be pedantic, and
    if you have more than one of these it is definitely less readable (and,
    therefore, not Pythonic):

    def meth(self, things=None):
    if things:
    self.things = things
    else:
    self.things = []

    > It's okay, I used to be a perl programmer too. It's nothing to be
    > ashamed of. :)


    Ah, now I would disagree with that as well! ;-)

    -Peter
    Peter Hansen, Sep 13, 2005
    #14
  15. Peter Hansen wrote:
    > def meth(self, things=None):
    > self.things = things or []
    >

    [snip]
    >
    > The alternative is fine too, but insisting on it would be pedantic, and
    > if you have more than one of these it is definitely less readable (and,
    > therefore, not Pythonic):
    >
    > def meth(self, things=None):
    > if things:
    > self.things = things
    > else:
    > self.things = []


    Probably worth pointing out that there is at least one more alternative:

    def meth(self, things=None):
    if things is None:
    things = []
    self.things = things

    I usually opt for this one, mainly because "things or []" makes me
    nervous -- it has different behavior if the user passes in an empty list:

    py> class Things1(object):
    .... def __init__(self, things=None):
    .... if things is None:
    .... things = []
    .... self.things = things
    ....
    py> class Things2(object):
    .... def __init__(self, things=None):
    .... self.things = things or []
    ....
    py> lst = []
    py> thing = Things1(lst)
    py> thing.things.append(100)
    py> thing.things, lst
    ([100], [100])
    py> lst = []
    py> thing = Things2(lst)
    py> thing.things.append(100)
    py> thing.things, lst
    ([100], [])

    That said, I do use "and" and "or" occasionally when I'm sure I don't
    have to worry about complications like the above. I've probably even
    used them in an assignment statement. ;)

    STeVe
    Steven Bethard, Sep 13, 2005
    #15
  16. gabor

    Jorgen Grahn Guest

    On Mon, 12 Sep 2005 12:52:52 +0200, gabor <> wrote:
    > hi,
    >
    > there are 2 versions of a simple code.
    > which is preferred?


    I don't know. Who cares?

    > ===
    > try:
    > text = line[n]
    > except IndexError:
    > text = 'nothing'
    > ===
    >
    >
    > which is the one you would use?


    The 'try' version. But I'd also ask myself how I could end up in a state where
    this part of the code is asked to find a string that doesn't exist, and if I
    really want it to keep running, with a made-up value.

    /Jorgen

    --
    // Jorgen Grahn <jgrahn@ Ph'nglui mglw'nafh Cthulhu
    \X/ algonet.se> R'lyeh wgah'nagl fhtagn!
    Jorgen Grahn, Sep 17, 2005
    #16
    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. Carl J. Van Arsdall
    Replies:
    4
    Views:
    488
    Bruno Desthuilliers
    Feb 7, 2006
  2. alf
    Replies:
    11
    Views:
    454
    7stud
    May 14, 2007
  3. Replies:
    3
    Views:
    297
    Paul Hankin
    Jan 25, 2008
  4. John Posner
    Replies:
    4
    Views:
    223
    Terry Reedy
    Apr 2, 2009
  5. Oltmans
    Replies:
    1
    Views:
    223
    J Kenneth King
    Apr 19, 2010
Loading...

Share This Page