my favorite line of py code so far

P

Peter Cacioppi

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.
 
C

Chris Angelico

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
 
P

Peter Cacioppi

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.
 
P

Peter Otten

Peter said:
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
.... 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)]
 
P

Peter Cacioppi

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.
 
C

Chris Angelico

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
 
P

Paul Rubin

Peter Cacioppi said:
[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.
 
P

Peter Otten

Peter said:
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.
 
S

Stefan Behnel

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
 
C

Chris Angelico

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
 
P

Peter Otten

Stefan said:
Peter Otten, 09.11.2013 12:49:

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,
4

so we're back to three. All seem to be established conventions rather than
obvious choices.
 
P

Peter Cacioppi

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
 
P

Peter Cacioppi

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...
 
C

Chris Angelico

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
 
P

Peter Cacioppi

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 ;)
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,821
Latest member
AleidaSchi

Latest Threads

Top