Alternative suggestion for conditional expressions (see PEP 308)

Discussion in 'Python' started by neblackcat, Jul 15, 2004.

  1. neblackcat

    neblackcat Guest

    Would anyone like to comment on the following idea?

    I was just going to offer it as a new PEP until it was suggested that
    I post it here for comment & consideration against PEP 308.

    I'm far from being a "language internist" (on Python or anything else)
    so go easy on me if this is stupid - it just seemed quite elegant to
    me as a relative newbie in town :)

    I also havent got a clue whether this would be easy or even possible
    to implement even if it was deemed a reasonable idea.

    -----------------------------------------------------------------------

    Abstract

    Implement C-like conditional expressions, but in a more
    flexible and "Python-like" way.

    Motivation

    The lack of conditional expressions combined with the lack
    of a 'switch' statement in Python tends to result in lots
    of 'if'/'elif' lines which often arent needed and which make
    code more verbose and sometimes (where there are a lot of
    them) harder to follow and more prone to mistakes than it
    needs to be.

    This PEP attempts to address that by proposing a
    'Pythonesque' conditional expressions language feature
    which fits well with existing language features
    and the way that conditional expressions are often
    simulated in current Python code by using temporary
    tuples, lists or dictionaries.


    Rationale

    It is currently possible to simulate conditional
    expressions in Python using constructs with
    temporary tuples/lists, such as:

    sColorName = ("Black","White")[Color == COLOR_WHITE]

    This works, but has two disadvantages:

    i) it involves packing and unpacking of a 'temporary'
    tuple, eg. ("Black","White") in the above, which
    has performance implications

    ii) this in turn means that *all* of the possible
    final values have to be valid (not just the one
    which will be actually selected), which is often
    not the case in a more real-world example, eg:

    r = (DEFAULT_RESULT, Database.Results[index])
    [IsValid(index)]

    In the above, 'Database.Results[index]' isn't
    defined to be valid if the 'index' value isn't,
    which means that this technique cant be used.

    Specification

    I therefore suggest a variation on the above
    syntax such as:

    sColorName = ?("Black","White")[Color == COLOR_WHITE]

    where the '?' identifies the immediately following
    tuple as a "conditional tuple" in which the tuple is
    not actually fully evaluated/stored. Instead,
    only the element specified by the immediately following
    index expression is evaluated and must be valid.

    This syntax could also apply to other sequence types,
    for example dictionaries:

    sColorName = ?{COLOR_RED:"Red",
    COLOR_BLUE:"Blue",
    COLOR_GREEN:"Green"}[ColorValue]

    Again, the conditional sequence is not fully evaluated/stored,
    so it doesnt matter if it is large and/or has members which
    arent evaluated given an index value which doesnt actually
    select them.

    Obviously, the above are just simple examples.
    neblackcat, Jul 15, 2004
    #1
    1. Advertising

  2. neblackcat

    Peter Hansen Guest

    neblackcat wrote:

    > Would anyone like to comment on the following idea?
    > Implement C-like conditional expressions, but in a more
    > flexible and "Python-like" way.

    [...]
    > I therefore suggest a variation on the above
    > syntax such as:
    >
    > sColorName = ?("Black","White")[Color == COLOR_WHITE]


    Funky uses of punctuation are about as non-Pythonic as you
    can get, so I doubt this idea would make it past the post...

    -Peter
    Peter Hansen, Jul 15, 2004
    #2
    1. Advertising

  3. neblackcat

    Larry Bates Guest

    Seems that every one of the examples can be done
    with a dictionary.

    sColorName = ("Black","White")[Color == COLOR_WHITE]

    use dictionary lookup:

    colorNameDict={COLOR_WHITE:"White", COLOR_BLACK: "BLACK"}
    sColorName=colorNameDict[Color]


    and

    sColorName = ?{COLOR_RED:"Red",
    COLOR_BLUE:"Blue",
    COLOR_GREEN:"Green"}[ColorValue]


    can be done as:

    colorNameDict={COLOR_RED:"Red",
    COLOR_BLUE:"Blue",
    COLOR_GREEN:"Green"}

    sColorName=colorNameDict[ColorValue

    you can also handle the "Default/undefined" case as:

    colorNameDict={COLOR_RED:"Red",
    COLOR_BLUE:"Blue",
    COLOR_GREEN:"Green"}

    sColorname=ColorNameDict.get(ColorValue, defaultvalue)

    or as I often do:

    colorNameDict={COLOR_RED:"Red",
    COLOR_BLUE:"Blue",
    COLOR_GREEN:"Green",
    'unknown': 'Unknown'}

    sColorname=colorNameDict.get(ColorValue, colorNameDict['unknown'])

    Since these dictionaries should be defined once and never
    inside a loop, I don't believe that performance is an issue.

    You can also simulate a switch statement as follows:

    def foo(args):
    print "in foo"

    def bar(args):
    print "in bar"

    def hee(args):
    print "in hee"

    def unknown(args):
    print "in unknown"

    switchDict={'one': foo, 'two': bar, 'three': hee,
    'default': unknown}

    switchvalue='one'
    switchFunction=switchDict.get(switchvalue, switchvalue['default'])
    switchFunction(args)

    Again you get excellent performance because dictionary lookups
    are blazingly fast. switchDict is only evaluated a single time
    (or should be) and is easily extendable by simply adding more
    switch values as keys.

    Larry Bates
    Syscon, Inc.

    "neblackcat" <> wrote in message
    news:...
    > Would anyone like to comment on the following idea?
    >
    > I was just going to offer it as a new PEP until it was suggested that
    > I post it here for comment & consideration against PEP 308.
    >
    > I'm far from being a "language internist" (on Python or anything else)
    > so go easy on me if this is stupid - it just seemed quite elegant to
    > me as a relative newbie in town :)
    >
    > I also havent got a clue whether this would be easy or even possible
    > to implement even if it was deemed a reasonable idea.
    >
    > -----------------------------------------------------------------------
    >
    > Abstract
    >
    > Implement C-like conditional expressions, but in a more
    > flexible and "Python-like" way.
    >
    > Motivation
    >
    > The lack of conditional expressions combined with the lack
    > of a 'switch' statement in Python tends to result in lots
    > of 'if'/'elif' lines which often arent needed and which make
    > code more verbose and sometimes (where there are a lot of
    > them) harder to follow and more prone to mistakes than it
    > needs to be.
    >
    > This PEP attempts to address that by proposing a
    > 'Pythonesque' conditional expressions language feature
    > which fits well with existing language features
    > and the way that conditional expressions are often
    > simulated in current Python code by using temporary
    > tuples, lists or dictionaries.
    >
    >
    > Rationale
    >
    > It is currently possible to simulate conditional
    > expressions in Python using constructs with
    > temporary tuples/lists, such as:
    >
    > sColorName = ("Black","White")[Color == COLOR_WHITE]
    >
    > This works, but has two disadvantages:
    >
    > i) it involves packing and unpacking of a 'temporary'
    > tuple, eg. ("Black","White") in the above, which
    > has performance implications
    >
    > ii) this in turn means that *all* of the possible
    > final values have to be valid (not just the one
    > which will be actually selected), which is often
    > not the case in a more real-world example, eg:
    >
    > r = (DEFAULT_RESULT, Database.Results[index])
    > [IsValid(index)]
    >
    > In the above, 'Database.Results[index]' isn't
    > defined to be valid if the 'index' value isn't,
    > which means that this technique cant be used.
    >
    > Specification
    >
    > I therefore suggest a variation on the above
    > syntax such as:
    >
    > sColorName = ?("Black","White")[Color == COLOR_WHITE]
    >
    > where the '?' identifies the immediately following
    > tuple as a "conditional tuple" in which the tuple is
    > not actually fully evaluated/stored. Instead,
    > only the element specified by the immediately following
    > index expression is evaluated and must be valid.
    >
    > This syntax could also apply to other sequence types,
    > for example dictionaries:
    >
    > sColorName = ?{COLOR_RED:"Red",
    > COLOR_BLUE:"Blue",
    > COLOR_GREEN:"Green"}[ColorValue]
    >
    > Again, the conditional sequence is not fully evaluated/stored,
    > so it doesnt matter if it is large and/or has members which
    > arent evaluated given an index value which doesnt actually
    > select them.
    >
    > Obviously, the above are just simple examples.
    Larry Bates, Jul 15, 2004
    #3
  4. neblackcat

    Jeff Shannon Guest

    Larry Bates wrote:

    >Seems that every one of the examples can be done
    >with a dictionary.
    >
    >


    While that may be true of the examples given here, it's not true of all
    cases. The one possible real advantage of a conditional expression, as
    I see it, is shortcutting. In cases where the conditionally-executed
    code has side effects, it can be important to ensure that *only* one
    branch is evaluated; creating an actual dictionary (whether permanent or
    temporary) will execute *all* branches. For example, using neblackcat's
    proposed syntax (even though I'm *not* fond of it):

    nextline = ?(FileOne.readline(), FileTwo.readline())[whichfile]

    In this case, since reading a line from a file advances the filepointer,
    executing both will result in a line being "lost" from the non-selected
    file. (I realize that in this specific example, one could use the
    conditional to select a file object and call readline() on the result of
    the conditional; I could also construct examples in which entirely
    different operations-with-side-effects are performed on each branch so
    that refactoring in that way isn't practical, or one branch is a string
    literal and the other has some side-effect, or whatever.)

    Note that, while I do think it's important to be aware of this
    distinction, I'm not advocating the proposed syntax (I'm rather leery of
    using punctuation like that, as Peter Hansen mentions) or even
    necessarily advocating for a conditional expression at all. I remain
    unconvinced of the need for an expression to do what can already be done
    with statements -- a conditional expression may be more concise, but
    conciseness more often hampers readability than helps it, and
    readability is very important. I've heard the arguments that using a
    multiline if/else construct in order to set up parameters for a function
    call is ugly, but I personally find that to be no worse than the
    ugliness of conditional expressions...

    Jeff Shannon
    Technician/Programmer
    Credit International
    Jeff Shannon, Jul 15, 2004
    #4
  5. neblackcat

    Phil Frost Guest

    On Thu, Jul 15, 2004 at 12:17:08PM -0700, Jeff Shannon wrote:
    > Larry Bates wrote:
    >
    > >Seems that every one of the examples can be done
    > >with a dictionary.

    >
    > While that may be true of the examples given here, it's not true of all
    > cases. The one possible real advantage of a conditional expression, as
    > I see it, is shortcutting. In cases where the conditionally-executed
    > code has side effects, it can be important to ensure that *only* one
    > branch is evaluated; creating an actual dictionary (whether permanent or
    > temporary) will execute *all* branches. For example, using neblackcat's
    > proposed syntax (even though I'm *not* fond of it):
    >
    > nextline = ?(FileOne.readline(), FileTwo.readline())[whichfile]
    >
    > ...


    Evaluation of the expressions could be deferred by using callables, like
    so:

    next = (lambda: fileone.readline(), lambda filetwo.readline())[which]()

    Or since in this example both sides of the tuple are already callables:

    next = (fileone.readline, filetwo.readline)[which]()

    But then really, is writing:

    if which: next=fileone.readline()
    else: next=filetwo.readline()

    all that bad?
    Phil Frost, Jul 15, 2004
    #5
  6. I was inclined to support PEP 308, but now wonder whether it's really
    needed.

    sColorName = ("Black","White")[Color == COLOR_WHITE]

    Could be:

    sColorName = Color == COLOR_WHITE and "Black" or "White"

    which takes avantantage of the short circuit evaluation

    sColorName= color == colorwhite and "white" or garbage

    This gives the correct result when only the first case needs to be
    evalutated.

    Colin W.

    neblackcat wrote:
    > Would anyone like to comment on the following idea?
    >
    > I was just going to offer it as a new PEP until it was suggested that
    > I post it here for comment & consideration against PEP 308.
    >
    > I'm far from being a "language internist" (on Python or anything else)
    > so go easy on me if this is stupid - it just seemed quite elegant to
    > me as a relative newbie in town :)
    >
    > I also havent got a clue whether this would be easy or even possible
    > to implement even if it was deemed a reasonable idea.
    >
    > -----------------------------------------------------------------------
    >
    > Abstract
    >
    > Implement C-like conditional expressions, but in a more
    > flexible and "Python-like" way.
    >
    > Motivation
    >
    > The lack of conditional expressions combined with the lack
    > of a 'switch' statement in Python tends to result in lots
    > of 'if'/'elif' lines which often arent needed and which make
    > code more verbose and sometimes (where there are a lot of
    > them) harder to follow and more prone to mistakes than it
    > needs to be.
    >
    > This PEP attempts to address that by proposing a
    > 'Pythonesque' conditional expressions language feature
    > which fits well with existing language features
    > and the way that conditional expressions are often
    > simulated in current Python code by using temporary
    > tuples, lists or dictionaries.
    >
    >
    > Rationale
    >
    > It is currently possible to simulate conditional
    > expressions in Python using constructs with
    > temporary tuples/lists, such as:
    >
    > sColorName = ("Black","White")[Color == COLOR_WHITE]
    >
    > This works, but has two disadvantages:
    >
    > i) it involves packing and unpacking of a 'temporary'
    > tuple, eg. ("Black","White") in the above, which
    > has performance implications
    >
    > ii) this in turn means that *all* of the possible
    > final values have to be valid (not just the one
    > which will be actually selected), which is often
    > not the case in a more real-world example, eg:
    >
    > r = (DEFAULT_RESULT, Database.Results[index])
    > [IsValid(index)]
    >
    > In the above, 'Database.Results[index]' isn't
    > defined to be valid if the 'index' value isn't,
    > which means that this technique cant be used.
    >
    > Specification
    >
    > I therefore suggest a variation on the above
    > syntax such as:
    >
    > sColorName = ?("Black","White")[Color == COLOR_WHITE]
    >
    > where the '?' identifies the immediately following
    > tuple as a "conditional tuple" in which the tuple is
    > not actually fully evaluated/stored. Instead,
    > only the element specified by the immediately following
    > index expression is evaluated and must be valid.
    >
    > This syntax could also apply to other sequence types,
    > for example dictionaries:
    >
    > sColorName = ?{COLOR_RED:"Red",
    > COLOR_BLUE:"Blue",
    > COLOR_GREEN:"Green"}[ColorValue]
    >
    > Again, the conditional sequence is not fully evaluated/stored,
    > so it doesnt matter if it is large and/or has members which
    > arent evaluated given an index value which doesnt actually
    > select them.
    >
    > Obviously, the above are just simple examples.
    Colin J. Williams, Jul 16, 2004
    #6
  7. Colin J. Williams <>
    wrote on Fri, 16 Jul 2004 09:49:22 -0400:
    > I was inclined to support PEP 308, but now wonder whether it's really
    > needed.
    > sColorName = ("Black","White")[Color == COLOR_WHITE]
    > Could be:
    > sColorName = Color == COLOR_WHITE and "Black" or "White"
    > which takes avantantage of the short circuit evaluation
    > sColorName= color == colorwhite and "white" or garbage
    > This gives the correct result when only the first case needs to be
    > evalutated.


    This works only as long as the results of the (true, false) choices
    both evaluate true:

    >>> def foo():

    .... print "eval foo"
    .... return "foo"
    ....
    >>> def bar():

    .... print "eval bar"
    .... return "bar"
    ....
    >>> False and foo() or bar()

    eval bar
    'bar'
    >>> True and foo() or bar()

    eval foo
    'foo'

    Looks good, right?

    >>> def foo():

    .... print "eval foo"
    .... return ""
    ....
    >>> False and foo() or bar()

    eval bar
    'bar'
    >>> True and foo() or bar()

    eval foo
    eval bar
    'bar'

    Alas. Not only does it evaluate both, causing who-knows-what side
    effects, it returns the wrong answer. Your Python nuclear missile
    launch program goes out of control. All die. O the embarassment.

    This is why we do actually need a ternary. It's not that the language
    lacks tools for choosing now, but that this behavior is so very easy to
    get wrong, and leads to very subtle bugs.

    The PEP 308 vote showed that at least 84% of the Python users wanted a
    ternary. A second vote between the four major choices would have
    obviously ended us up with the (if <cond1>: <expr1> elif <cond2>:
    <expr2> ... else: <exprN>) form, which is about as Pythonically
    unambiguous as you can get.

    At the time, my opinion was that I didn't need a ternary often enough
    to care. Sometimes I want to modify some math depending on a boolean,
    and in that case I can just treat it as 0 or 1:

    >>> 5 + 3 * True

    8

    And the rest of the time, it's easy (if tedious) to just write:

    >>> if True: a=foo()

    .... else: a=bar()
    ....
    eval foo
    >>> a

    ''

    However, the ease of doing the and...or and ()[] versions wrong, and
    how unbelievably ugly the latter is, have changed my mind from "this is
    not important" to "this is something Python really does need, after
    all".

    --
    <a href="http://kuoi.asui.uidaho.edu/~kamikaze/"> Mark Hughes </a>
    "The void breathed hard on my heart, turning its illusions to ice, shattering
    them. Was reborn, then, free to scrawl own design on this morally blank
    world. Was Rorschach." --Alan Moore, _Watchmen #6_, "The Abyss Gazes Also"
    Mark 'Kamikaze' Hughes, Jul 16, 2004
    #7
  8. Flame suit on.

    - add a switch-case statement :
    I do miss a switch-case in Python.
    The interpreter can't really optimize if/elif as a dictionary lookup,
    because what if there is a AND or OR clause, or if the object has defined
    a __cmp__ method with side effects ? This would be pervert...

    switch color:
    case 1:
    name = 'red'
    case 2:
    name = 'blue'
    case 3:
    case 4:
    name = 'colorblind'

    Could use a 'break' (like in C) or not (cleaner).

    - add a switch-case statement which can return a value.
    Problem : you need a new keyword for that, which is a bad thing... and it
    starts to look like lisp...

    I think the ternary operator is a half-baked solution to a more general
    problem ; it is useful as a little shortcut like " x ? 'Yes' : 'No' but
    doing more with it leads to obfuscation.

    Still, something lacks in Python... just like the break-n-levels.
    =?iso-8859-15?Q?Pierre-Fr=E9d=E9ric_Caillaud?=, Jul 19, 2004
    #8
  9. Pierre-Frédéric Caillaud <>
    wrote on Mon, 19 Jul 2004 19:31:07 +0200:
    > Flame suit on.
    > - add a switch-case statement :
    > I do miss a switch-case in Python.
    > The interpreter can't really optimize if/elif as a dictionary lookup,
    > because what if there is a AND or OR clause, or if the object has defined
    > a __cmp__ method with side effects ? This would be pervert...
    > switch color:
    > case 1:
    > name = 'red'
    > case 2:
    > name = 'blue'
    > case 3:
    > case 4:
    > name = 'colorblind'
    > Could use a 'break' (like in C) or not (cleaner).
    > - add a switch-case statement which can return a value.
    > Problem : you need a new keyword for that, which is a bad thing... and it
    > starts to look like lisp...


    Simpler version that already works:
    colornames = {
    1: "red",
    2: "blue",
    }
    print colornames.get(color, "colorblind")

    > I think the ternary operator is a half-baked solution to a more general
    > problem ; it is useful as a little shortcut like " x ? 'Yes' : 'No' but
    > doing more with it leads to obfuscation.


    It's more for selecting between function calls than for constants. A
    common idiom with a ternary in Java is:
    value = test == null ? null : test.something();

    That doesn't happen as often in Python, but choosing between different
    methods depending on a flag happens more often.

    > Still, something lacks in Python... just like the break-n-levels.


    At least there's a consistent and easy way to do that. Use
    exceptions, or extract your inner loops into a method, and return when
    you want to "break out".

    --
    <a href="http://kuoi.asui.uidaho.edu/~kamikaze/"> Mark Hughes </a>
    "Spontaneous deliquescence is now a protected condition under the Americans with
    Disabilities Act." -John J. Reilly, "Cthuluism and the Cold War"
    Mark 'Kamikaze' Hughes, Jul 20, 2004
    #9
    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. Christoph Becker-Freyseng

    PEP for new modules (I read PEP 2)

    Christoph Becker-Freyseng, Jan 15, 2004, in forum: Python
    Replies:
    3
    Views:
    360
    Gerrit Holl
    Jan 16, 2004
  2. Reinhold Birkenfeld
    Replies:
    62
    Views:
    1,076
    Andrew Koenig
    Oct 16, 2005
  3. Roger
    Replies:
    2
    Views:
    294
    Gabriel Genellina
    Sep 12, 2006
  4. Colin J. Williams

    Conditional expressions - PEP 308

    Colin J. Williams, Jan 30, 2007, in forum: Python
    Replies:
    4
    Views:
    320
    Ziga Seilnacht
    Jan 31, 2007
  5. Neatu Ovidiu Gabriel

    Suggestion: PEP for popping slices from lists

    Neatu Ovidiu Gabriel, Aug 8, 2013, in forum: Python
    Replies:
    13
    Views:
    131
    Terry Reedy
    Aug 8, 2013
Loading...

Share This Page