FAQ
my fav so far is this


_ = lambda c : lambda x : c(*x)


c can be any calleable and x any iterable, but I tend to use it with a class, and then map _(class) over the result of a zip.


It must be in the library somewhere, but I haven't found it. I'm never sure what to call it, so I just reroll it into _ as needed. It's pretty easy for me to remember, but I'll probably tattoo it on my chest just in case.

Search Discussions

  • Chris Angelico at Nov 8, 2013 at 10:32 pm

    On Sat, Nov 9, 2013 at 9:22 AM, Peter Cacioppi wrote:
    my fav so far is this

    _ = lambda c : lambda x : c(*x)

    c can be any calleable and x any iterable, but I tend to use it with a class, and then map _(class) over the result of a zip.

    It must be in the library somewhere, but I haven't found it. I'm never sure what to call it, so I just reroll it into _ as needed. It's pretty easy for me to remember, but I'll probably tattoo it on my chest just in case.

    So... for any given class, it returns a tweaked version that unpacks
    an iterable of its arguments instead of taking separate args.
    Interesting, perhaps, but not something that'll be needed in the
    stdlib. But as a demo of how easily Python primitives can be combined
    into some fairly elegant code, I think this is as good as any!


    ChrisA
  • Peter Cacioppi at Nov 8, 2013 at 10:43 pm
    Chris said:


    "So... for any given class, it returns a tweaked version that unpacks
    an iterable of its arguments instead of taking separate args. "


    It works with any calleable (not just any class), but otherwise your summary is spot on.


    "Interesting, perhaps, but not something that'll be needed in the stdlib."


    Fair enough. In the interest of self promotion, I'm calling it the Cacioppi combinator. The tattoo apt is for Tues.
  • Peter Otten at Nov 9, 2013 at 7:12 am

    Peter Cacioppi wrote:


    my fav so far is this

    _ = lambda c : lambda x : c(*x)

    c can be any calleable and x any iterable, but I tend to use it with a
    class, and then map _(class) over the result of a zip.

    It must be in the library somewhere, but I haven't found it. I'm never
    sure what to call it, so I just reroll it into _ as needed. It's pretty
    easy for me to remember, but I'll probably tattoo it on my chest just in
    case.

    You mean

    class P:
    ... def __init__(self, x, y):
    ... self.x = x
    ... self.y = y
    ... def __repr__(self):
    ... return "Point(x={0.x}, y={0.y})".format(self)
    ...
    P(1, 2)
    Point(x=1, y=2)
    _ = lambda c: lambda x: c(*x)
    list(map(_(P), zip([1,2,3], [6, 5, 4])))
    [Point(x=1, y=6), Point(x=2, y=5), Point(x=3, y=4)]


    ? While the obvious approach would be

    [P(*args) for args in zip([1,2,3], [6, 5, 4])]
    [Point(x=1, y=6), Point(x=2, y=5), Point(x=3, y=4)]


    there is also itertools.starmap():

    from itertools import starmap
    list(starmap(P, zip([1,2,3], [6, 5, 4])))
    [Point(x=1, y=6), Point(x=2, y=5), Point(x=3, y=4)]
  • Peter Cacioppi at Nov 9, 2013 at 9:23 am
    Peter Otten said:




    ">>> _ = lambda c: lambda x: c(*x)
    list(map(_(P), zip([1,2,3], [6, 5, 4])))
    [Point(x=1, y=6), Point(x=2, y=5), Point(x=3, y=4)]


    ? While the obvious approach would be

    [P(*args) for args in zip([1,2,3], [6, 5, 4])]
    [Point(x=1, y=6), Point(x=2, y=5), Point(x=3, y=4)] "


    I would have coded
    map(_(P), zip([1,2,3], [6, 5, 4]))

    Which is very concise and (to me) quite clear. Forgive me for having a bias for fewer characters.


    Are you saying it's always preferable to avoid map? Is map going to be deprecated?


    I sometimes use map, sometimes comprehensions. I suspect other people do the same, that's why the language supports map and comprehensions.


    "there is also itertools.starmap(): "


    Thanks, that's a bit closer to what I am doing. To me the pure combinator is more appealing than starmap, but the presence of starmap explains why the library wouldn't need the combinator.
  • Chris Angelico at Nov 9, 2013 at 9:28 am

    On Sat, Nov 9, 2013 at 8:23 PM, Peter Cacioppi wrote:
    I sometimes use map, sometimes comprehensions. I suspect other people do the same, that's why the language supports map and comprehensions.

    I think map is fine if you can use a named function, but if you can't
    come up with a descriptive name for what you're doing, a comprehension
    is probably better (as it'll have the code right there). Mapping _
    across everything tells you nothing about what it's actually doing.


    ChrisA
  • Paul Rubin at Nov 9, 2013 at 9:49 am

    Peter Cacioppi <peter.cacioppi@gmail.com> writes:
    [P(*args) for args in zip([1,2,3], [6, 5, 4])]
    [P(x,y) for x,y in zip(...)]

    Are you saying it's always preferable to avoid map?

    Not always. Depends on context, partly subjective.

    I sometimes use map, sometimes comprehensions. I suspect other people
    do the same, that's why the language supports map and comprehensions.

    Comprehensions came along later and there was some noise made about
    eliminating map for a while, though I think that's died down.

    "there is also itertools.starmap(): "
    Thanks, that's a bit closer to what I am doing. To me the pure
    combinator is more appealing than starmap,

    You could look at the functools module too, particularly
    functools.partial. For that matter, you could also try Haskell. It's
    even more concise, and this flavor of code is easier to keep reliable
    when there's compile-time type checking.
  • Peter Otten at Nov 9, 2013 at 11:49 am

    Peter Cacioppi wrote:


    Peter Otten said:


    ">>> _ = lambda c: lambda x: c(*x)
    list(map(_(P), zip([1,2,3], [6, 5, 4])))
    [Point(x=1, y=6), Point(x=2, y=5), Point(x=3, y=4)]

    ? While the obvious approach would be
    [P(*args) for args in zip([1,2,3], [6, 5, 4])]
    [Point(x=1, y=6), Point(x=2, y=5), Point(x=3, y=4)] "

    I would have coded
    map(_(P), zip([1,2,3], [6, 5, 4]))
    Which is very concise and (to me) quite clear. Forgive me for having a
    bias for fewer characters.

    Consider developing a bias for self-explanatory names ;)

    Are you saying it's always preferable to avoid map?

    No. I'm saying that if you have a problem with multiple solutions you should
    pick the boringly obvious one if you plan to reuse or publish the code.


    There is no obvious meaning attached to _ -- so don't use it.

    Is map going to be deprecated?

    Not to my knowledge. I use it when I already have a function ready
    to be called with the items in a sequence. Continuing the Point example that
    could be


    map(Point, xvals, yvals)


    or


    map(Point.from_tuple, xypairs)

    I sometimes use map, sometimes comprehensions. I suspect other people do
    the same, that's why the language supports map and comprehensions.

    "there is also itertools.starmap(): "

    Thanks, that's a bit closer to what I am doing. To me the pure combinator
    is more appealing than starmap, but the presence of starmap explains why
    the library wouldn't need the combinator.

    I found only a single use of starmap on my machine (and one more in the
    stdlib)


    # in redis.client
    all_cmds = ''.join(starmap(connection.pack_command,
                                [args for args, options in commands]))


    and frankly, I would prefer


    all_cmds = "".join(
         connection.pack_command(*args) for args, options in commands)


    which by some strange coincidence also requires fewer letters to type.
  • Stefan Behnel at Nov 9, 2013 at 12:41 pm

    Peter Otten, 09.11.2013 12:49:
    There is no obvious meaning attached to _ -- so don't use it.

    Not quite true. Depending on the context, the obvious meanings of "_" in
    Python are either


    1) "ignore me", e.g. in


         _, b = some_tuple


    or


    2) "this is a non-public thing", as in


         class Xyz:
             _private = 1


    or


    3) "I am the translation function", as commonly used in (HTML) templates:


         _("translation key here")




    None of the three meanings applies to the OP's example, AFAICT.


    Stefan
  • Chris Angelico at Nov 9, 2013 at 12:45 pm

    On Sat, Nov 9, 2013 at 11:41 PM, Stefan Behnel wrote:
    2) "this is a non-public thing", as in

    class Xyz:
    _private = 1

    Your three meanings all have the etymology of "ignore me", but I would
    distinguish this one from the others. An underscore used on its own
    has meaning; an underscore as part of a larger token has quite
    different meaning, and can have any of several - "private-ish" (as
    above), "mangle me" (double leading, no trailing), "magic" (dunder -
    double leading/double trailing), and "word separator"
    (between_multiple_words_in_an_identifier). Your other two examples are
    what we're talking about here, though.


    ChrisA
  • Peter Otten at Nov 9, 2013 at 1:49 pm

    Stefan Behnel wrote:


    Peter Otten, 09.11.2013 12:49:
    There is no obvious meaning attached to _ -- so don't use it.
    Not quite true. Depending on the context, the obvious meanings of "_" in
    Python are either

    1) "ignore me", e.g. in

    _, b = some_tuple

    or

    2) "this is a non-public thing", as in

    class Xyz:
    _private = 1

    This doesn't fit the bill provided we're discussing the name _ rather than
    any underscore.
    3) "I am the translation function", as commonly used in (HTML) templates:

    _("translation key here")


    None of the three meanings applies to the OP's example, AFAICT.

    I can come up with one more, the last non-None result calculated in the
    interactive interpreter,

    2*2
    4
    _
    4


    so we're back to three. All seem to be established conventions rather than
    obvious choices.
  • Peter Cacioppi at Nov 10, 2013 at 8:57 am
    Chris said :


    "I think map is fine if you can use a named function, but if you can't
    come up with a descriptive name for what you're doing, a comprehension
    is probably better (as it'll have the code right there). Mapping _
    across everything tells you nothing about what it's actually doing"


    OK, this makes a lot of sense. (Any my apologies to Peter Otten if my previous post was overly snarky).


    How about this? I put the following in my catchall_utility.py module


       # the oneArg combinator takes a multi-argument calleable
       # and returns the equivalent single argument calleable
       oneArg = lambda c: lambda x : c(*x)




    With example code


       map(oneArg(P), zip([1,2,3], [6, 5, 4]))


    To my mind the idea that oneArg(P) is a calleble that behaves exactly like P, with the only difference being oneArg(P) accepts P's arguments packed into a single iterable, is very intuitive.


    I actually find the oneArg version more readable than the comprehension that unpacks explicitly using *. At this point I probably have equal experience coding Lisp and Py, with the latter more recent, so I don't think this bias can be chalked up to "experienced functional programmer, beginner py programmer".


    To be clear, I was never really intending to keep the


       _ = lambda c : lambda x : c(*x)
       map(oneArg(P), zip([1,2,3], [6, 5, 4]))


    code snippets in my final work product. The purpose of this thread was too fish around for ideas on what to replace it with when I execute the "use the unit tests to facilitate refactoring for better names and more professional idioms" step.


    (We never, ever, skip that step, right?)


    Although it is unlikely you will convince me to use the comprehension in this sort of situation, it's possible someone could convince me to use starmap with P instead of map with oneArg(P). Those two techniques are fully equivalent. But, to my mind, the latter just feels right, and I find that I write fewer bugs when I use idioms that resonate.


    Thanks again, good thread for me
  • Chris Angelico at Nov 10, 2013 at 10:23 am

    On Sun, Nov 10, 2013 at 7:57 PM, Peter Cacioppi wrote:
    Chris said :

    "I think map is fine if you can use a named function, but if you can't
    come up with a descriptive name for what you're doing, a comprehension
    is probably better (as it'll have the code right there). Mapping _
    across everything tells you nothing about what it's actually doing"

    How about this? I put the following in my catchall_utility.py module

    # the oneArg combinator takes a multi-argument calleable
    # and returns the equivalent single argument calleable
    oneArg = lambda c: lambda x : c(*x)

    Now it has a name, so I could imagine you importing it into modules
    and using it usefully. I'd be inclined to call it something along the
    lines of "unpacked" but that's just bikeshedding.

    ... I find that I write fewer bugs when I use idioms that resonate.

    Absolutely! The unfortunate truth, though, is that idioms that
    resonate with you _and nobody else_ are just as big a problem as bugs,
    because they're unmaintainable. So hopefully what you're doing will
    make sense to other people too!


    ChrisA
  • Peter Cacioppi at Nov 10, 2013 at 8:59 am
    Sorry, typo, meant to say


    To be clear, I was never really intending to keep the


       _ = lambda c : lambda x : c(*x)
       map(_(P), zip([1,2,3], [6, 5, 4]))


    code snippets in my final work product. The purpose of this thread was too fish around for ideas on what to replace it with...
  • Peter Cacioppi at Nov 11, 2013 at 12:00 am
    Chris said :


    "Absolutely! The unfortunate truth, though, is that idioms that
    resonate with you _and nobody else_ are just as big a problem as bugs,
    because they're unmaintainable. So hopefully what you're doing will
    make sense to other people too! "


    There is some truth in what you say ... but in this case we're talking about an algorithmically trivial portion of a project for which I am basically BDFL. So as long as I'm not totally in left field, I'm going with what feels truthy to me.


    Also,


       lambda c : lambda x : c(*x)


    would make a sweet tattoo. Much better than some Kanji that might as well translate into "dumb white guy" for all I know ;)

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedNov 8, '13 at 10:22p
activeNov 11, '13 at 12:00a
posts15
users5
websitepython.org

People

Translate

site design / logo © 2022 Grokbase