News for hackers. Stuff that matters.
Re:The fate of reduce() in Python 3000 (2005) by avian on Tuesday January 01, 2019 @09:57AM (#18800404)
> Also, once map(), filter() and reduce() are gone, there aren't a whole lot of places where you really need [lambda].

By far the most common use of lambda for me is the "key" argument for sort() or sorted(). As in something like:

foo.sort(key=lambda x:x[2])

Yes, there are itemgetter and attrgetter in operator module, but I always have to look up their names and writing the lambda expression is simply faster.

Re:The fate of reduce() in Python 3000 (2005) by raverbashing on Tuesday January 01, 2019 @05:52PM (#18802929)
Yeah, I don't get the "hate" for the functional operations, though comprehensions have better syntax

And no, I don't want to 'def' every small function I might need, pep-8 recommendations aside. Key as mentioned is one use, but there are other cases where it's especially useful

Re:The fate of reduce() in Python 3000 (2005) by nszceta on Tuesday January 01, 2019 @02:33PM (#18801790)
itemgetter and attrgetter are compiled C functions called by cpython https://github.com/python/cpython/blob/master/Modules/_opera...
Re:The fate of reduce() in Python 3000 (2005) by masklinn on Tuesday January 01, 2019 @02:43PM (#18801838)
They mean faster to write, not that it's necessarily faster to execute (though the difference is likely immaterial).
Re:The fate of reduce() in Python 3000 (2005) by thomasahle on Tuesday January 01, 2019 @02:34PM (#18801795)
Right, though for those uses something like the swift {$0[0]} or haskell (!!0) just seems a lot more of convenient.
Re:The fate of reduce() in Python 3000 (2005) by malvosenior on Tuesday January 01, 2019 @01:34PM (#18801498)
> I think dropping filter() and map() is pretty uncontroversial; filter(P, S) is almost always written clearer as [x for x in S if P(x)]

Performance reasons aside, I strongly disagree with this statement. Anyone can see that `filter` is going to apply the predicate to the iteratable in the first statement. The second statement is super awkward, declares a temp var `x` which to my limited Pythonic eyes looks like it's just calling the identity function on `x` that comes back from the "filter".

Again, I have no doubt Python is optimized to perform better with the second form, but that seems a limitation in the interpreter. The syntax to non-Python devs is pretty raunchy imho.

Re:The fate of reduce() in Python 3000 (2005) by goto11 on Tuesday January 01, 2019 @05:01PM (#18802663)
I agree with you for the example with a named function P, but as Guido points out, filter predicates are typically simple expression which you don't want to create a named function for. So it would be say `filter(lambda x: x < 17, S)` versus `[x for x in S if x < 17]`. I think the second one is nicer even if the repeated x is ugly. Neither is great though. The comprehension syntax assumes filters are accompanied by maps. A filter without a map is a somewhat ugly special-case.

The real issue is the lack of a lambda syntax with a pythonic feel.

Re:The fate of reduce() in Python 3000 (2005) by Tarean on Tuesday January 01, 2019 @02:52PM (#18801888)
I am used to haskell's syntax, does this become more readable once you get used to it? The haskell equivalent would be

    [x | x <- s, p x]
Re:The fate of reduce() in Python 3000 (2005) by roenxi on Tuesday January 01, 2019 @04:23PM (#18802468)
In many senses this is a style thing, but:

There is going to be a pretty sharp break between people who accept that working with a collection deserves special syntax support and those who don't. The readability issue for me isn't that the syntax doesn't look nice, it is that I've invested years into making a very efficient little mental space that deals with "data2 = fn(data1)" style constructs and I want to use it here like I do everywhere else.

Some silly-high percentage of for loops can be cast into this data2 = fn(data1). Why am I being told that it isn't readable? If this isn't easy to read, then something is wrong with the function syntax.

A chaining operator, to recast fn3(fn2(fn1(data))) => data > fn1 > fn2 > fn3 with reduce is much more readable, debuggable and easy to reason about than having to remember what syntax todays language uses to talk about collections and how that works in to the flow of data in my program.

Re:The fate of reduce() in Python 3000 (2005) by pseudalopex on Tuesday January 01, 2019 @10:31PM (#18803988)
The list comprehension syntax is just set notation with Python keywords instead of symbols. Haskell, JavaScript, and Julia have similar syntax. It's also similar to the equivalent loop.

Which of these is clearer?

    [x * y for x in S if P(x) > 0]
    map(lambda x: x * y, filter(lambda x: P(x) > 0, S))
Re:The fate of reduce() in Python 3000 (2005) by dorfsmay on Tuesday January 01, 2019 @10:36AM (#18800529)
reduce() is still available in the functools module.

I highly recommend to become familiar with the functools, itertools and collections modules to anybody using Python and not using them regularly.

Re:The fate of reduce() in Python 3000 (2005) by stochastic_monk on Tuesday January 01, 2019 @10:50AM (#18800591)
I’ve really come to miss reduce in Python’s builtins since std::accumulate has become a staple in my C++ development. It seems surprising that with Python 3’s increased support for functional concepts, it would relegate reduce to the standard library.
Re:The fate of reduce() in Python 3000 (2005) by masklinn on Tuesday January 01, 2019 @02:46PM (#18801850)
Not really, increasing support for functional concept was never a goal of Python 3 (or at all), it was mostly incidental and it did regress in other ways than just shoving the (relatively little used due to the existence of min/max/any/all) out of the builtins e.g. while extended unpacking was added, unpacking iterable function parameters was removed.
Re:The fate of reduce() in Python 3000 (2005) by geezerjay on Wednesday January 02, 2019 @01:18AM (#18804530)
+1 for the std::accumulate reference, and I'll add an honorable mention of std::transform which since C++17 also runs in parallel.
Re:The fate of reduce() in Python 3000 (2005) by _asummers on Tuesday January 01, 2019 @10:51AM (#18800595)
This is broadly true across language. In Java, it was Collections, List, Elixir it's Enum, Python is your mentioned stdlib namespaces. Knowing your collection-ey stdlib functions will only help your code be more idiomatic and likely performant.
Re:The fate of reduce() in Python 3000 (2005) by black-tea on Tuesday January 01, 2019 @03:52PM (#18802283)
Indeed, those modules are essential for doing anything in Python beyond small scripts.
Re:The fate of reduce() in Python 3000 (2005) by sifoobar on Tuesday January 01, 2019 @12:57PM (#18801291)
I spent some time comparing Python's [0] map/filter and comprehensions against Snigl [1].

Comprehensions are just plain faster, especially if you perform say filter and map at the same time.

That and a lambda implementation that only a mother could love, lack of tail call optimization etc.

What bothers me about comprehensions is they come with a separate set of rules, like LOOP in Common Lisp or templates in C++; but I'm pretty sure the restrictions are part of what makes them fast.

[0] https://gitlab.com/sifoo/snigl/blob/master/bench/seq.py

[1] https://gitlab.com/sifoo/snigl/blob/master/bench/seq.sl

Re:The fate of reduce() in Python 3000 (2005) by klyrs on Tuesday January 01, 2019 @01:17PM (#18801405)
Agreed, this made my eye twitch:

> filter(P, S) is almost always written clearer as [x for x in S if P(x)]

sure, Guido, if you think it's clear that the variable x is in the enclosing scope...

Re:The fate of reduce() in Python 3000 (2005) by joshuamorton on Tuesday January 01, 2019 @01:30PM (#18801486)
Python 3 changed this, iirc. Comprehension no longer leak.
Re:The fate of reduce() in Python 3000 (2005) by jks on Tuesday January 01, 2019 @02:46PM (#18801852)
It's still an assignment operation, and you can still get weird effects in the enclosing scope. I did something like this by accident:

    Python 3.7.1 (default, Nov 28 2018, 21:47:25)
    Type 'copyright', 'credits' or 'license' for more information
    IPython 6.4.0 -- An enhanced Interactive Python. Type '?' for help.

    In [1]: lookup = {}

    In [2]: [x for (x, lookup[x]) in ('ab', 'cd', 'ef') if x in lookup]
    Out[2]: ['a', 'c', 'e']

    In [3]: lookup
    Out[3]: {'a': 'b', 'c': 'd', 'e': 'f'}
Re:The fate of reduce() in Python 3000 (2005) by zephyrfalcon on Tuesday January 01, 2019 @03:12PM (#18802007)
It appears to work without list comprehensions as well:

    Python 3.7.1 (default, Nov  6 2018, 18:49:54)
    Type 'copyright', 'credits' or 'license' for more information
    IPython 7.1.1 -- An enhanced Interactive Python. Type '?' for help.

    In [1]: lookup = {}

    In [2]: a, lookup[a] = 'xy'

    In [3]: a
    Out[3]: 'x'

    In [4]: lookup
    Out[4]: {'x': 'y'}
I wasn't previously aware that this was possible, but I guess it's no different from

    a = 'x'
    lookup[a] = 'y'  # i.e. lookup['x'] = y
Re:The fate of reduce() in Python 3000 (2005) by joshuamorton on Tuesday January 01, 2019 @03:05PM (#18801967)
The whacky thing there isn't the list comprehension though, it's the implicit assignment of `lookup[x]`. If you desugar it some (which isn't really possible, but

    [(x, lookup.setdefault(x, y)) for (x, y) in ('ab', 'cd', 'ef')]
comes close), what's happening makes a lot more sense. It works exactly the same way as any other scope: first checks locally, then nonlocally or globally. You're modifying a nonlocal. The syntax you're using to modify the nonlocal is surprising, but that's the surprising part, not the ability to modify a nonlocal.
Re:The fate of reduce() in Python 3000 (2005) by theamk on Wednesday January 02, 2019 @01:34PM (#18808674)
I'd desugar it like this:

    >>> lookup = {}
    >>> for (x, lookup[x]) in ('ab', 'cd', 'ef'):
    ...     pass
    ... 
    >>> lookup
    {'a': 'b', 'c': 'd', 'e': 'f'}
This makes is much more clear that there is just a double assignment, and that comprehension are pretty close to regular `for` statement.

(this was a great example btw -- I write python3 a lot, and I was staring at it for a long time before Icould figure it out)

Re:The fate of reduce() in Python 3000 (2005) by jks on Wednesday January 02, 2019 @12:40AM (#18804405)
I think I was personally surprised by two assumptions that I implicitly held, both of which disappear when you write them down:

1. The syntax of comprehensions led me to think that they introduce some kind of a variable binding, such as `let` in many Lisps, and that binding `lookup[x]` would have been a syntax error. Of course Python didn't introduce anything like that for comprehensions, and it's just a normal assignment operation, with an extra scope inserted in Python 3 to stop `x` leaking into the enclosing scope.

2. Because of the swap idiom `x, y = y, x` I thought tuple assignment happens somehow in parallel, so my code should have caused an undefined variable error, even if it is not a syntax error. But of course it just evaluates the right hand side first and then assigns to the left hand side in left-to-right order, which the language reference https://docs.python.org/3/reference/simple_stmts.html#assign... notes "sometimes result[s] in confusion" (near the end of the section).

Re:The fate of reduce() in Python 3000 (2005) by klyrs on Tuesday January 01, 2019 @05:29PM (#18802813)
Okay that's pretty sweet actually. I write a lot of legacy-compatible code, so I'm kinda behind on Py3. Maybe that's my 2019 project.
Re:The fate of reduce() in Python 3000 (2005) by masklinn on Tuesday January 01, 2019 @02:47PM (#18801857)
> Comprehensions are just plain faster, especially if you perform say filter and map at the same time.

Comprehensions are often slower if you're applying a function regardless, definitely so if that function is a builtin.

Re:The fate of reduce() in Python 3000 (2005) by dang on Tuesday January 01, 2019 @01:56PM (#18801612)
Re:The fate of reduce() in Python 3000 (2005) by wodenokoto on Tuesday January 01, 2019 @09:43AM (#18800351)
Why were map and filter kept? What can you do that cannot be as easily done with generator expressions?
Re:The fate of reduce() in Python 3000 (2005) by duckerude on Tuesday January 01, 2019 @10:19AM (#18800477)
I'm sometimes tempted to use it in loops, when

  for x in map(func, iterable):
      ...
is cleaner than

  for x in (func(y) for y in iterable):
      ...
and shorter than

  for y in iterable:
      x = func(y)
      ...
But that mostly only makes sense if you already have a suitable named function (e.g. str), and I usually end up going with the third variant anyway.

There's an analogous case with filter and `if not cond: continue`.

map and filter calls are trivially rewritten to generator expressions, but it's not necessarily an improvement.

Re:The fate of reduce() in Python 3000 (2005) by studentik on Tuesday January 01, 2019 @09:56AM (#18800397)
Coconut has many examples of functional programming techniques that cannot be easily done with python: https://coconut.readthedocs.io/en/master/DOCS.html

Strangely FP is not popular among python developers.

Re:The fate of reduce() in Python 3000 (2005) by danharaj on Tuesday January 01, 2019 @10:36AM (#18800531)
It's a pain in the ass to write functional code in python because the syntax is not optimized for it. A functional programming language makes lambda and (partial) application as cheap as possible, which Python does not.
Re:The fate of reduce() in Python 3000 (2005) by AlexCoventry on Tuesday January 01, 2019 @02:59PM (#18801945)
I think you can get 95% of the benefit of FP just by favoring abstractions which present a functional interface. Python hasn't really gotten in my way, in that respect, though it would be nice to have first-class persistent data structures with structural sharing.
Re:The fate of reduce() in Python 3000 (2005) by mlevental on Tuesday January 01, 2019 @02:23PM (#18801749)
is coconut used in production? seems like a really bad idea?
Re:The fate of reduce() in Python 3000 (2005) by studentik on Tuesday January 01, 2019 @08:13PM (#18803493)
It's python after all, so why not?
Re:The fate of reduce() in Python 3000 (2005) by masklinn on Tuesday January 01, 2019 @02:51PM (#18801880)
> What can you do that cannot be as easily done with generator expressions?

Technically nothing, but at the same time if you already have a function (especially a builtin) map/filter is more convenient and can be faster. And they're first-class objects which comprehensions are not, which can be convenient.

The goal is not necessarily to prune all redundancies: reduce already existed when sum/min/max/any/all were added, despite the latter being fairly simple special cases of the former (not quite entirely for min/max, but not far).

Re:The fate of reduce() in Python 3000 (2005) by InclinedPlane on Tuesday January 01, 2019 @07:23PM (#18803306)
Why bother having any control logic other than conditionals and gotos? Because they signal intent directly.
Re:The fate of reduce() in Python 3000 (2005) by taraploughman on Tuesday January 01, 2019 @04:53PM (#18802623)
Does anyone know the origin story of reduce/filter in Python? It seemed interesting. I remember watching a talk by Guido. He mentioned that someone submitted a PR with it, and that it was very complete, so he merged it. But I'm curious what the decision making process was like for Python back then, or if there even was a formal process.

Programming language archaeology is a field that ought to get more attention.