FAQ
Hey people. If I want to put conditions in a lambda function, how would I
go about that?

def test(string):
if string[:3] == 'yes:
return 1
else:
return 0

I'd like to make something like this a lambda function. Is that possible?

Mike

--
Michael P. Soulier, TD12, SKY Tel: 613-765-4699 (ESN: 39-54699)
Optical Networks, Nortel Networks, SDE Pegasus
"...the word HACK is used as a verb to indicate a massive amount
of nerd-like effort." -Harley Hahn, A Student's Guide to UNIX
Nortel Linux User's Group Ottawa: (internal) http://nlug.ca.nortel.com

Search Discussions

  • Fredrik Lundh at Nov 3, 2000 at 7:51 pm
    Michael P. Soulier wrote
    Hey people. If I want to put conditions in a lambda function, how would I
    go about that?

    def test(string):
    if string[:3] == 'yes:
    return 1
    else:
    return 0

    I'd like to make something like this a lambda function. Is that possible?
    nope. lambdas can only contain simple expressions.

    also see:

    http://www.python.org/doc/FAQ.html#6.9
    6.9. Why can't lambda forms contain statements?

    "...the only advantage of using a lambda form instead of
    a locally-defined function is that you don't need to invent
    a name for the function..."

    </F>
  • Michael P. Soulier at Nov 3, 2000 at 8:18 pm

    In article <KGEM5.4144$jv2.474395 at newsc.telia.net>, Fredrik Lundh wrote:
    nope. lambdas can only contain simple expressions.

    also see:

    http://www.python.org/doc/FAQ.html#6.9
    6.9. Why can't lambda forms contain statements?

    "...the only advantage of using a lambda form instead of
    a locally-defined function is that you don't need to invent
    a name for the function..."
    Thanks. I guess I'm still in that Perl mentality where I'm trying to do
    many things on one line.

    I was looking for a simple way of grabbing all lines that began with a
    the string #LOADDATA. In perl I'd do this:

    open (FILE, "file") or die "Can't open file: $!";
    @contents = grep { /^\#LOADDATA/ } <FILE>;

    In python I'm doing it this way...

    filecontents = open(filename, "r").readlines()
    filecontents = filter(filterloaddata, filecontents)

    def filterloaddata(string):
    if string[:9] == '#LOADDATA':
    return 1
    else:
    return 0

    I guess it'd just be nice to do it without the function. I'm still
    learning Python though...

    Mike

    --
    Michael P. Soulier, TD12, SKY Tel: 613-765-4699 (ESN: 39-54699)
    Optical Networks, Nortel Networks, SDE Pegasus
    "...the word HACK is used as a verb to indicate a massive amount
    of nerd-like effort." -Harley Hahn, A Student's Guide to UNIX
    Nortel Linux User's Group Ottawa: (internal) http://nlug.ca.nortel.com
  • Fredrik Lundh at Nov 3, 2000 at 8:40 pm

    Michael wrote:
    filecontents = open(filename, "r").readlines()
    filecontents = filter(filterloaddata, filecontents)

    def filterloaddata(string):
    if string[:9] == '#LOADDATA':
    return 1
    else:
    return 0
    oh, but "string[:9] == '#LOADDATA' is an expression, which
    returns zero if false, and a non-zero (1, actually) if true.

    try this:

    filter(lambda s: s[:9] == '#LOADDATA', filecontents)

    or better:

    filter(lambda s: s.startswith('#LOADDATA'), filecontents)

    or, if you're using 2.0:

    [line for line in filecontents if line.startswith('#LOADDATA')]

    </F>
  • Michael P. Soulier at Nov 3, 2000 at 9:39 pm

    In article <XoFM5.4146$jv2.475484 at newsc.telia.net>, Fredrik Lundh wrote:
    oh, but "string[:9] == '#LOADDATA' is an expression, which
    returns zero if false, and a non-zero (1, actually) if true.

    try this:

    filter(lambda s: s[:9] == '#LOADDATA', filecontents)

    or better:

    filter(lambda s: s.startswith('#LOADDATA'), filecontents)

    or, if you're using 2.0:

    [line for line in filecontents if line.startswith('#LOADDATA')]
    Ah, gotcha.

    Thanks,

    Mike

    --
    Michael P. Soulier, TD12, SKY Tel: 613-765-4699 (ESN: 39-54699)
    Optical Networks, Nortel Networks, SDE Pegasus
    "...the word HACK is used as a verb to indicate a massive amount
    of nerd-like effort." -Harley Hahn, A Student's Guide to UNIX
    Nortel Linux User's Group Ottawa: (internal) http://nlug.ca.nortel.com
  • Niki Spahiev at Nov 3, 2000 at 9:28 pm
    03.11.2000, 22:18:23, Michael P. Soulier wrote:

    MPS> I was looking for a simple way of grabbing all lines that began with a
    MPS> the string #LOADDATA. In perl I'd do this:

    MPS> open (FILE, "file") or die "Can't open file: $!";
    MPS> @contents = grep { /^\#LOADDATA/ } <FILE>;

    MPS> In python I'm doing it this way...

    MPS> filecontents = open(filename, "r").readlines()
    MPS> filecontents = filter(filterloaddata, filecontents)

    MPS> def filterloaddata(string):
    MPS> if string[:9] == '#LOADDATA':
    MPS> return 1
    MPS> else:
    MPS> return 0

    And why not this

    filecontents = open(filename, "r").readlines()
    filecontents = filter(lambda s: s[:9] == '#LOADDATA', filecontents)

    --
    Best regards,
    Niki Spahiev
  • Paul Prescod at Nov 3, 2000 at 10:29 pm

    Niki Spahiev wrote:
    ...

    And why not this

    filecontents = open(filename, "r").readlines()
    filecontents = filter(lambda s: s[:9] == '#LOADDATA', filecontents)
    If you're using Python 2, here's a more verbose, but perhaps more
    readable way to do the same thing:

    filecontents = [line for line in filecontents
    if line.startswith("#LOADDATA")]

    Paul Prescod
  • Alex Martelli at Nov 3, 2000 at 10:13 pm
    "Michael P. Soulier" <msoulier at nortelnetworks.com> wrote in message
    news:8tv6if$m79$1 at bmerhc5e.ca.nortel.com...
    [snip]
    Thanks. I guess I'm still in that Perl mentality where I'm trying to do
    many things on one line.
    Nothing intrinsically wrong with that.
    I was looking for a simple way of grabbing all lines that began with a
    the string #LOADDATA. In perl I'd do this:

    open (FILE, "file") or die "Can't open file: $!";
    @contents = grep { /^\#LOADDATA/ } <FILE>;
    SO verbose? Tch...! Python 2...:

    contents = [x for x in open("file").readlines()
    if x.startswith('#LOADDATA')]

    (you CAN cram it onto 1 line, but 1.5 read better:-).


    Alex
  • Joshua Muskovitz at Nov 3, 2000 at 9:16 pm
    Although the general case of adding conditionals in a lambda isn't allowed,
    if you can restructure the requirement to an expression, then you can make
    it work. For your example:
    def test(string):
    if string[:3] == 'yes:
    return 1
    else:
    return 0
    You can do the following:

    Python 1.5.2 (#0, Apr 13 1999, 10:51:12) [MSC 32 bit (Intel)] on win32
    Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
    a = lambda x: x[:3] == 'yes'
    a('')
    a('yes')
    1
    a('yess')
    1
    >>>

    This works because an equality comparison expression already returns 0 or 1.
    You can get creative (or silly, depending on how you look at it) by taking
    that result and using it inside something larger:
    a = lambda x: ['does not start with "yes"', 'starts with "yes"'][x[:3]
    == 'yes']
    a('')
    'does not start with "yes"'
    a('yes')
    'starts with "yes"'
    a('yess')
    'starts with "yes"'
    >>>

    And of course, you get can get much sillier than this, but you get the idea.

    -- josh





    -----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
    http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
    -----== Over 80,000 Newsgroups - 16 Different Servers! =-----
  • Bryn Keller at Nov 3, 2000 at 9:22 pm

    One possibility is to use the when function from lazy.py:

    from lazy import *
    filterloaddata = lambda x:when(x[:9] == "#LOADDATA", 1, 0)
    The when function also works with lazy expressions, which is why it's in the lazy
    module.
    lazy.py is part of the Xoltar Toolkit, available at
    http://www.sourceforge.net/projects/xoltar-toolkit . The package also contains
    other tools that someone who's keen on lambdas might appreciate.

    Hope that helps,

    Bryn


    "Michael P. Soulier" wrote:
    Hey people. If I want to put conditions in a lambda function, how would I
    go about that?

    def test(string):
    if string[:3] == 'yes:
    return 1
    else:
    return 0

    I'd like to make something like this a lambda function. Is that possible?

    Mike

    --
    Michael P. Soulier, TD12, SKY Tel: 613-765-4699 (ESN: 39-54699)
    Optical Networks, Nortel Networks, SDE Pegasus
    "...the word HACK is used as a verb to indicate a massive amount
    of nerd-like effort." -Harley Hahn, A Student's Guide to UNIX
    Nortel Linux User's Group Ottawa: (internal) http://nlug.ca.nortel.com
  • Alex Martelli at Nov 3, 2000 at 10:28 pm
    "Michael P. Soulier" <msoulier at nortelnetworks.com> wrote in message
    news:8tv48r$kn8$1 at bmerhc5e.ca.nortel.com...
    Hey people. If I want to put conditions in a lambda function, how would
    I go about that?
    Carefully; Python doesn't have built-in 'conditions' as expressions
    (only as statements, which can't live inside a lambda). But you
    can fake it, much of the time, with indexing or other tricks. E.g.:

    def foobar(whop):
    if whop>"pohrw": return "foox"
    else: return "barbar"

    ==

    foobar = lambda whop: ("foox", "barbar")[whop<="pohrw"]

    def test(string):
    if string[:3] == 'yes:
    return 1
    else:
    return 0

    I'd like to make something like this a lambda function. Is that
    possible?

    Hey, is this a Brainbench test...?-)

    test = lambda string: return string.startswith('yes')


    Alex
  • Greg Ball at Nov 3, 2000 at 11:29 pm
    Michael P. Soulier wrote
    filecontents = filter(filterloaddata, filecontents)

    def filterloaddata(string):
    if string[:9] == '#LOADDATA':
    return 1
    else:
    return 0
    This is very easily done using a lambda.

    filecontents = filter(lambda s: s[:9]=='#LOADDATA', filecontents)

    You just have to know that the relational operators are expressions and
    can appear anywhere (they are 1 or 0 for true or false...). This is how I
    use filter() most of the time.

    You can do much more complicated things to make up for lack of control
    flow in expressions, using logical operators and indexing, but it's a case
    of diminishing returns.

    -Greg Ball
  • Donald O'Donnell at Nov 4, 2000 at 3:12 am

    Sure you can:

    L = lambda string: string[:3] == 'yes'
    L('yesterday')
    1
    L('tomorrow')

    In fact you can do some pretty powerful stuff without using any
    statements at all, only logical expressions.

    For example:
    lambda sep: sep=='/' and 2 or sep==',' and 3 or sep=='-' and 4 or 5
    this will return 2, 3, 4 for arguments '/', ',', '-' and 5 for anything
    else.

    To quote from the Python Reference Manual (Section 5.10 Boolean
    operations):

    "Note that neither `and` nor `or` restrict the value and type they
    return
    to 0 or 1, but rather return the last evaluated argument. ..."

    There's more in the manual. Check it out, and have fun.

    There's-more-to-logical-expressions-than-true-and-false-ly yours,

    Don O'Donnell


    "Michael P. Soulier" wrote:
    Hey people. If I want to put conditions in a lambda function, how would I
    go about that?

    def test(string):
    if string[:3] == 'yes:
    return 1
    else:
    return 0

    I'd like to make something like this a lambda function. Is that possible?

    Mike

    --
  • Erik Max Francis at Nov 4, 2000 at 5:12 am

    "Michael P. Soulier" wrote:

    I'd like to make something like this a lambda function. Is that
    possible?
    Sure:

    lambda s: s[:3] == 'yes'

    It's not possible in the general case, where you have more involved
    control structures being used.

    --
    Erik Max Francis / max at alcyone.com / http://www.alcyone.com/max/
    __ San Jose, CA, US / 37 20 N 121 53 W / ICQ16063900 / &tSftDotIotE
    / \ All the people in his neighborhood turn around and get mad and sing
    \__/ Public Enemy
    Official Buh rules / http://www.alcyone.com/max/projects/cards/buh/
    The official rules to the betting card game, Buh.
  • Steve Horne at Nov 9, 2000 at 12:48 pm

    On 3 Nov 2000 19:39:07 GMT, msoulier at nortelnetworks.com (Michael P. Soulier) wrote:

    Hey people. If I want to put conditions in a lambda function, how would I
    go about that?

    def test(string):
    if string[:3] == 'yes:
    return 1
    else:
    return 0
    The case you are trying to do is handled by other answers, but there
    is a simple trick to doing this for conditions in general...

    ([no_result, yes_result] [(condition) + 1])

    ie - put the possible answers in a list and then use the condition to
    derive the subscript.

    --
    Steve Horne
    sh at ttsoftware.co.uk
  • Alex Martelli at Nov 9, 2000 at 1:49 pm
    "Steve Horne" <sh at ttsoftware.co.uk> wrote in message
    news:sr6l0t0ofsorqhojv77deecu2gjusgc8o9 at 4ax.com...
    On 3 Nov 2000 19:39:07 GMT, msoulier at nortelnetworks.com (Michael P.
    Soulier) wrote:
    Hey people. If I want to put conditions in a lambda function, how
    would I
    [snip]
    is a simple trick to doing this for conditions in general...

    ([no_result, yes_result] [(condition) + 1])

    ie - put the possible answers in a list and then use the condition to
    derive the subscript.
    This is (roughly) ok *IF AND ONLY IF* it is OK to evaluate both results
    independently of the condition's value.

    Why "roughly": this will work if condition is either 0 or 1, but will
    fail in different ways for most other values of 'condition'. Python
    accepts many more kinds of values as 'true-or-false conditions'; any
    non-zero number is 'true', an empty sequence is 'false' and other
    sequences are 'true', etc.

    It's easy to do the same by switching your idiom to:

    (yes_result, no_result)[not (condition)]

    as the "not" will obey exactly Python's general rules for what is
    true and what is false, and it WILL return exactly 0 if condition
    is true, exactly 1 if condition is false.


    The 'deeper' problem remains: this will fail in some cases in
    which if/else would work just fine, e.g....:

    if foo != 0:
    return 1/foo
    else:
    return 23

    is NOT equivalent to:

    return (1/foo,23)[not (foo!=0)]

    because *both entries in the tuple will be evaluated, whatever
    foo is worth*. So, when foo==0, the 'indexing' approach will
    fail with a division-by-zero exception, while if/else would
    give no problem.

    This is because Python's general approach to evaluation is
    "eager" (all arguments to a function are fully evaluated before
    the function is called) and not "lazy" (only evaluate args
    if and when their values are actually needed).


    For cases in which this may be a problem, a closer approach
    to 'conditionals' (if/else behavior) is supplied by Python's
    operators "and" and "or". THOSE (and those only) avoid "too
    much zeal" (eagerness) in evaluating their operands; their
    semantics specifies "short-circuit" evaluation -- the right
    side operand gets evaluated at all _ONLY_ if its value is
    actually needed to give the operator's result.


    For "and": if the left-side operand's value is "false", then
    the whole "and" operation returns "false", and the right-side
    operand *is NOT evaluated at all*. If the left-side operand's
    value is "true", then the whole "and" operation returns as
    its value the value of the right-side operand.

    In other words, there IS semantic equivalence between:

    return a and b

    and

    temp = a
    if temp:
    return b
    else:
    return temp

    for ANY expressions a and b (I've used an explicit 'temp'
    in the 'equivalent-semantics' construct to underline that
    a is not multiply evaluated...).


    "or" works similarly, i.e. it also "short-circuits", but
    "the other way around": the equivalence becomes, then:

    return a or b

    and

    temp = a
    if temp:
    return temp
    else:
    return b


    So, the full semantic equivalence to:
    if condition:
    return yes_result
    else:
    return no_result

    can *almost* be built up as an expression by:

    return (condition and yes_result) or no_result

    where the "almost" comes from the risk that "yes_result"
    may evaluate to false... in which case the "no_result"
    would unwontedly be evaluated and returned!


    One trick to bypass even this issue may be...:

    return ((condition and (yes_result,)) or (no_result,))[0]

    By making the right-side of the "and" into a one-item
    tuple, we know Python will _never_ evaluate it as "false"!
    (We then also need to make the no_result into a similar
    one-item tuple, so we can end by getting the 0-th [only]
    element in either case...!).


    So much subtlety is hardly ever needed. Most of the
    time, either the indexing-trick or the simpler and/or
    trick will be provably OK (if we know it's OK to
    evaluate both results, and/or we know the yes_result
    cannot be false). If any cases subsist where the
    "full trick" seems necessary, I think I would always,
    as an issue of style, prefer to eschew the lambda in
    favour of a local named-function, where I will need
    no dirty tricks whatsoever to express my wishes...
    lambda is supposed to be there *as a convenience*
    (it's basically just saving you the trouble of thinking
    up a name for some inconsequential thingy) -- why keep
    using it in cases where it turns out to be so massively
    *IN*-convenient, as to force such complexities...?!-)

    Say, for example, that I need to write a function
    with the signature:
    def invseq(numseq, onzero)
    and the semantics: return a sequence with the numeric
    inverse 1/x of each number x in numseq, except that,
    if x==0, 'onzero' needs to be used in lieu of 1/x in
    that spot in the result-sequence.

    I think the cleanest, most readable solution is:

    def invseq(numseq, onzero):
    def inv(x, default=onzero):
    if x: return 1/x
    else: return default
    return [inv(x) for x in numseq]

    or, in older Python versions (or for list-comprehension-
    haters:-):

    def invseq(numseq, onzero):
    def inv(x, default=onzero):
    if x: return 1/x
    else: return default
    return map(inv, numseq)

    even though the lambda-equivalent is more compact, and,
    in this case, can be coded with the simple-and/or-trick:

    def invseq(numseq, onzero):
    return map(lambda x,default=onzero: ((x!=0) and (1/x)) or default,
    numseq)

    It seems to me that _naming_ the "invert" subfunction,
    in this case, increases clarity, even though the line
    count becomes 4 (moderate-length) lines versus one (a
    bit too-long) line. An issue of style, of course.


    Now, say we must handle _two_ sequences (of the same
    length), returning a sequence that, at each spot,
    has x/y (where x is the corresponding element of
    the first sequence, y of the second one) _except_
    that, for those spots in which y is 0, x+1 is to be
    returned instead. The simple-trick...:

    def divseqs(seqx, seqy):
    return map(lambda x,y: ((y!=0) and (x/y)) or x+1, seqx, seqy)

    doesn't work any more -- at those spots where x==0,
    we'd be wrongly returning 1 instead! We need the
    full-trick in this case...:

    def divseqs(seqx, seqy):
    return map(lambda x,y: (((y!=0) and (x/y,)) or (x+1,))[0], seqx, seqy)

    and it seems to me that its readability is truly abysmal.
    Wouldn't you rather write...:

    def divseqs(seqx, seqy):
    def div(x, y):
    if y: return x/y
    else: return x+1
    return map(div, seqx, seqy)

    or equivalently (Python 2):

    def divseqs(seqx, seqy):
    def div(x, y):
    if y: return x/y
    else: return x+1
    return [div(x,y) for x, y in zip(seqx,seqy)]

    ...?


    Alex
  • Steve Horne at Nov 9, 2000 at 3:45 pm
    I agree with most of what you say, and I confess I wasn't thinking of
    it. Also, I have no idea why I suddenly thought list subscripts
    started at 1.

    However, did you realise how easy a lazy version is to create...

    Using tuples (which do seem clearer than my list version, and probably
    better in other ways to)...

    (no_value,yes_value) [condition]

    This can be adapted as follows...

    ((lambda : no_value, lambda : yes_value) [condition]) ()

    That is, the indexing operation selects which lambda to evaluate.

    Of course the lambdas may need some default parameters, and could
    easily get a bit awkward syntactically. But it should work.

    So with the case using division...

    ((lambda : 0, lambda j=j : 1/j) [j != 0]) ()

    --
    Steve Horne
    sh at ttsoftware.co.uk
  • Alex Martelli at Nov 9, 2000 at 5:03 pm
    "Steve Horne" <sh at ttsoftware.co.uk> wrote in message
    news:psgl0t4bvnm5o76phoaqqldrrs44uoafmh at 4ax.com...
    [snip]
    However, did you realise how easy a lazy version is to create...
    No, I hadn't thought of it -- it *is* neat:-).

    Using tuples (which do seem clearer than my list version, and probably
    better in other ways to)...

    (no_value,yes_value) [condition]

    This can be adapted as follows...

    ((lambda : no_value, lambda : yes_value) [condition]) ()

    That is, the indexing operation selects which lambda to evaluate.

    Of course the lambdas may need some default parameters, and could
    easily get a bit awkward syntactically. But it should work.
    The syntax is rapidly headed towards an "Obfuscated Python
    Context", yes, but the _concept_ behind it is nevertheless
    cool.

    So with the case using division...

    ((lambda : 0, lambda j=j : 1/j) [j != 0]) ()
    Or, to avoid default-valued parms,

    ((lambda j:0, lambda j:1/j)[j!=0])(j)

    Not that readability and clarity change much, here...:-)


    Alex
  • Steve Horne at Nov 9, 2000 at 5:20 pm

    On Thu, 09 Nov 2000 15:45:09 +0000, Steve Horne wrote:
    This can be adapted as follows...

    ((lambda : no_value, lambda : yes_value) [condition]) ()
    I should say this isn't real lazy evaluation, for several reasons...

    1. Because the lambdas don't remember the results after the first
    evaluation, so in some expressions they could be evaluated
    repeatedly. A good implementation of lazy evaluation would try
    hard to avoid this.

    2. Because there is no intelligence in the order of evaluation. A
    good lazy implementation would evaluate the easiest subexpressions
    first in hope of optimising out the more complex subexpressions.

    3. Because the lambdas don't transparently act as values when needed.
    You have to explicitly evaluate them.

    Even so, it allows a few lazy-evaluation style tricks.

    --
    Steve Horne
    sh at ttsoftware.co.uk
  • Ben Wolfson at Nov 9, 2000 at 7:27 pm
    In article <psgl0t4bvnm5o76phoaqqldrrs44uoafmh at 4ax.com>,
    Steve Horne wrote:
    I agree with most of what you say, and I confess I wasn't thinking of
    it. Also, I have no idea why I suddenly thought list subscripts
    started at 1.

    However, did you realise how easy a lazy version is to create...

    Using tuples (which do seem clearer than my list version, and probably
    better in other ways to)...

    (no_value,yes_value) [condition]

    This can be adapted as follows...

    ((lambda : no_value, lambda : yes_value) [condition]) ()

    That is, the indexing operation selects which lambda to evaluate.

    Of course the lambdas may need some default parameters, and could
    easily get a bit awkward syntactically. But it should work.

    So with the case using division...

    ((lambda : 0, lambda j=j : 1/j) [j != 0]) ()
    Or:
    from lambdabuse import If
    (lambda: If(0, lambda: 1/0, If(1, 1, lambda: 1/0)))()
    1



    --
    BTR | It is a symptome of Melancholy to be afraid of death, and yet
    sometimes to desire it; this latter I have often discovered in my selfe, and
    thinke noe man ever desired life as I have sometimes Death.
    -- Thomas Browne, _Religio Medici_

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedNov 3, '00 at 7:39p
activeNov 9, '00 at 7:27p
posts20
users12
websitepython.org

People

Translate

site design / logo © 2022 Grokbase