News for hackers. Stuff that matters.
Re:Why I'm still using Python by atoav on Friday December 30, 2022 @01:43PM (#34188346)
One of the single language features that makes me stay with python is list comprehensions. So maybe something like that:

    stuff = [cleanup(s) for s in stuff if s.unprocessed]
This, the way you can handle/manipulate strings and the powerful included libraries make python a good language.

Downsides? Dependency managment, tooling, speed

Re:Why I'm still using Python by sodapopcan on Friday December 30, 2022 @02:32PM (#34188976)
List comprehensions are great but certainly not unique to Python.
Re:Why I'm still using Python by snowpid on Friday December 30, 2022 @02:20PM (#34188824)
List Comprehension is just syntax for functional coding (filter, map) but a very good one!
Re:Why I'm still using Python by von_lohengramm on Friday December 30, 2022 @03:28PM (#34189683)
I may be the outlier here, but I have a very hard time comprehending list comprehensions. They've always seemed like a SQL query compressed into a single line (or two if you're lucky!): readable when it's simple, Lovecraftian when it's not. I've always found the functional pipeline style much more readable and much easier to explain to others, especially with IDE type hints.
Re:Why I'm still using Python by int_19h on Friday December 30, 2022 @03:57PM (#34189987)
SQL queries are sequence comprehensions!

Python comprehensions in particular are unfortunate because the flow of the query, like in SQL, is not linear - the projection part is written first, but happens last. Thus, reading a non-trivial query requires moving back and forth to resolve the references.

Compare that to C# LINQ, which is also a kind of sequence comprehension. That one not only has linear syntax where the data flow in the query is strictly left to right, but it's explicitly defined by mapping it to functional pipeline style. Thus, it ends up being a strict improvement on the latter.

(Another example of "good" sequence comprehensions in this sense is XQuery FLWOR)

Re:Why I'm still using Python by maxbond on Friday December 30, 2022 @04:34PM (#34190383)
IMHO the key to legible comprehensions is to use them only to express composition and to put the logic into verbosely named functions.

Chained pipelines (`foo.filter(...).map(...)`) are fine to me, certainly more verbose then comprehensions for better & worse, but I get lost in pipelines expressed as nested functions (`map(filter(a, ...), ...)`).

Re:Why I'm still using Python by dragonwriter on Friday December 30, 2022 @04:36PM (#34190401)
> they’ve always seemed like a SQL query compressed into a single line (or two if you’re lucky!):

If its more than a very simple expression, with one simple for, and no if or very simple if, I try to use at least (more, with parens, if necessary): one line for the result expression, one line for each for clause, and one line for each if clause.

But, while the boundary is subjective, it doesn’t take much before functional pipeline style is clearer (Python lambdas being more limited and syntacticaly cumbersome, functional pipeline style isn’t as clean in Python as it is in other languages, though.)

Re:Why I'm still using Python by snowpid on Sunday January 01, 2023 @06:55AM (#34205622)
it depends on your problem but in many cases simple is enough imho. There are map and filter in python avalaible. I just didnt need to use them.
Re:Why I'm still using Python by ogogmad on Friday December 30, 2022 @03:51PM (#34189928)
Being pedantic: This isn't true in Haskell, because list comprehensions can use pattern matching, while map+filter can't.

  heads :: [[a]] -> [a]
  heads xs = [y | (y:ys) <- xs]

  -- heads [[1],[],[2,3]] == [1,2]
Doing the above using maps and filters looks very different:

  heads' = map head . filter (not . null)
Python doesn't really support Haskell-like pattern matching, so the above doesn't apply.
Re:Why I'm still using Python by pdonis on Friday December 30, 2022 @04:56PM (#34190580)
> Python doesn't really support Haskell-like pattern matching

It does as of 3.10:

https://peps.python.org/pep-0622/

Not as sophisticated as what Haskell can do, I'm sure, but I think it's a good addition to Python.

Re:Why I'm still using Python by ulucs on Friday December 30, 2022 @05:02PM (#34190616)
The thing you're looking for is easily found with a Hoogle search for type

    (a -> Maybe b) -> [a] -> [b]
Which yields mapMaybe: https://hackage.haskell.org/package/base-4.17.0.0/docs/Data-.... so you end up with

    heads = mapMaybe safeHead
Re:Why I'm still using Python by ogogmad on Saturday December 31, 2022 @06:21AM (#34195436)
That doesn't look like a direct substitute that covers every case.
Re:Why I'm still using Python by pharmakom on Friday December 30, 2022 @04:46PM (#34190494)
Sorry, but Python list comprehensions are not very good compared to other languages.
Re:Why I'm still using Python by snowpid on Sunday January 01, 2023 @06:52AM (#34205605)
why?
Re:Why I'm still using Python by pharmakom on Sunday January 01, 2023 @12:28PM (#34208442)
In F# list comprehensions, for example, you can have full blown expressions such as loops and conditionals. This is really nice for templating.

    [
      if List.isEmpty items then
        p “No items”
      else
        ul
          [
             for item in items do
               li [ item ]
          ]
    ]
Re:Why I'm still using Python by snowpid on Monday January 02, 2023 @06:41AM (#34216883)
so?

if len(items) == 0: return [p("no items")] else: ul( [ li(item) for item in items ] )

I am also not a fan of convoluted list comprehension (in python) so powerful is not necessarly a good thing.

Re:Why I'm still using Python by pharmakom on Monday January 02, 2023 @08:09AM (#34217474)
That only works in a single purpose function.

And consider this example:

    [
      h1 “items”

      if List.isEmpty items then
        p “No items”
      else
        ul
          [
             for item in items do
               li [ item ]
          ]
    ]
Re:Why I'm still using Python by snowpid on Monday January 02, 2023 @09:33AM (#34218246)
h1(items) + rest of my code... I might see what are you using for but I am not sure if concenating implicitly (or with line breaks / spaces) is a good design decision for a language.
Re:Why I'm still using Python by pharmakom on Monday January 02, 2023 @09:55AM (#34218489)
The yield keyword is optional. The result is a List<HtmlElement>

I don’t see how this can be done in Python without using mutation, which makes code scattered across multiple statements

Re:Why I'm still using Python by snowpid on Monday January 02, 2023 @11:26AM (#34219726)
your example has also multiply statements. The question is more important: Which syntax to a more generally better readability. (as this is solvable in most languages)
Re:Why I'm still using Python by pharmakom on Monday January 02, 2023 @11:52AM (#34220133)
No, it is built from pure expressions. This means that our list is defined in one block (everything within the [ ] tokens) and immutability is enforced by the compiler.
Re:Why I'm still using Python by curiousgal on Friday December 30, 2022 @03:50PM (#34189927)
C#'s LINQ is far more powerful in my opinion.
Re:Why I'm still using Python by matsemann on Friday December 30, 2022 @04:15PM (#34190201)
I have a completely opposite reaction, one of the things I hate the most with Python is its list-incomprehensions. They quickly become hard to read and very imperative, instead of declarative. Something like stuff.filter(it.unprocessed).map(cleanup(it)) conveys the intention behind each statement a hundred times better. And list comprehensions becomes impossible to reason about once they involve flatmapping or other relative simple functional expressions.
Re:Why I'm still using Python by sodapopcan on Friday December 30, 2022 @04:41PM (#34190444)
I agree very much so. List comprehensions and can be nice and concise and readable in many situations, but due to the whole "one true way" thing in Python, they're used in every situation, even when a map/reduce/filter etc would be better. Although since there are no pipes, I sorta get it.
Re:Why I'm still using Python by MrVandemar on Friday December 30, 2022 @05:31PM (#34190876)
Definite agreement. I started a long time ago with Python2, and what attracted me was how simple and readable the syntax was.

With Python3 there is a move towards "idiomatic" Python code, which to me means moving away from clear and concise to the old programmer trap/readability nightmare of "look how many things I can get it to do with one line of code!"

Re:Why I'm still using Python by fbdab103 on Friday December 30, 2022 @08:32PM (#34192405)
Let's not even talk about those insane people who use nested list comprehensions.

Not sure if it would make my top-5 Python-hate list (1-4 would probably be dedicated to packaging and distribution), but list comprehensions definitely feel like a misstep that contributes little value to the language.

Re:Why I'm still using Python by ilyash on Saturday December 31, 2022 @02:55AM (#34194532)
Yep. What bothers me is when you start looking at list comprehension is that you don't know if it's filter(), map(), or a combination. You have to read the list comprehension till the end to understand.
Re:Why I'm still using Python by cortesoft on Friday December 30, 2022 @04:30PM (#34190337)
I feel like this is a lot cleaner and more clear in Ruby:

stuff = stuff.map {|s| cleanup(s) if s.unprocessed }.compact

Re:Why I'm still using Python by nequo on Friday December 30, 2022 @05:08PM (#34190662)
Only knowing Python and not Ruby, your snippet looks confusing to me.

1. What does the anonymous function return if s.unprocessed is false?

2. If it returns nothing, do I get a missing value element in the iterable that results from map?

3. And what does it mean to compact the result of the map call?

The Python snippet raises none of these questions in me. But it could be because I am familiar with Python’s quirks.

Re:Why I'm still using Python by cortesoft on Friday December 30, 2022 @05:16PM (#34190735)
The compact gets rid of all the null values returned when unprocessed is false.

Interestingly I wasn't exactly sure what the python code would do, which is why I used the compact. In the python code, does 'stuff' end up only having the result of the cleanup function for items that are unprocessed? Or will it have all of the items, and the ones where unprocessed returns false just end up being returned unmodified?

My Ruby version returns the processed subset of items that were unprocessed. The python version was not clear to me, since I don't know what happens if s.unprocessed returns false.

So basically, it sounds like we were both confused by the same parts of the language we are unfamiliar with... what happens to elements where s.unprocessed is false? It was clear to me that in Ruby it returns a nil, but I have no idea in Python... what happens?

Re:Why I'm still using Python by nequo on Friday December 30, 2022 @05:26PM (#34190816)
Huh, our mutual confusion is interesting indeed! Thank you for teaching me something about Ruby. What compact does makes sense.

Python’s list comprehension combines map and filter.

  [process(s) for s in stuff if s.unprocessed]
is equivalent to

  map process (filter isUnprocessed stuff)
in Haskell.
Re:Why I'm still using Python by baq on Friday December 30, 2022 @05:26PM (#34190827)
Nothing, literally. This is map+filter optimized (or a for+if+append but using dedicated opcodes for efficiency) so you don’t have to do multiple passes and/or create temporary lists with superfluous elements.
Re:Why I'm still using Python by empthought on Friday December 30, 2022 @07:54PM (#34192035)
I feel that this is not the case.
Re:Why I'm still using Python by spicyusername on Friday December 30, 2022 @04:44PM (#34190480)
I almost always prefer to read nested loops and conditionals than list comprehensions.

I find the syntax of list comprehensions ugly and inscrutable.

Re:Why I'm still using Python by xvedejas on Friday December 30, 2022 @04:48PM (#34190517)
Additionally I find that it's easier to add complexity to the loops; once you want to start doing nontrivial things in a list comprehension, you often need to rewrite it into a loop first anyway.
Re:Why I'm still using Python by Spivak on Friday December 30, 2022 @06:05PM (#34191178)
> It's easier to add complexity to the loops

This is basically selling point for comprehensions. You can't add complexity to them so any comprehension you see fits a few common loop patterns you can grok immediately.

If you see an actual for loop in python it means "pay attention something odd is probably going on."

Re:Why I'm still using Python by gorgoiler on Saturday December 31, 2022 @03:39AM (#34194724)
* * *
Re:Why I'm still using Python by Kwpolska on Friday December 30, 2022 @06:04PM (#34191172)
You can easily replace this with various forms of map/filter in many other popular languages. Assuming cleanUp is a single-argument function/static method:

    // JS
    stuff = stuff.filter(s => s.unprocessed).map(cleanUp);

    // Java
    stuff = stuff.stream().filter(s -> s.unprocessed).map(Main::cleanUp).toList();
    
    // C#
    stuff = stuff.Where(s => s.Unprocessed).Select(CleanUp).ToList();
Java streams and C# LINQ extensions also expose other nice data processing functions, eg. sum, takeWhile, distinct.

And if you like Python’s dictionary comprehensions:

    {str(n): n * 2 for n in range(1, 11)}
you can use ToDictionary in C#:

    Enumerable.Range(start: 1, count: 10).ToDictionary(n => n.ToString(), n => n * 2);
Re:Why I'm still using Python by skitter on Friday December 30, 2022 @08:03PM (#34192123)
These are also easier to read and write than the Python version, as you can just follow the dataflow from top to bottom (or left to right if it fits into a single line). In Python, your eyes have to jump around to find where to the next bit of processing happens, not just in comprehensions but also with map/filter/list/len and co which are freestanding functions for some reason.
Re:Why I'm still using Python by gsinclair on Friday December 30, 2022 @08:07PM (#34192155)
“You can…”

Sure, but the Python code is so much nicer.

I don’t even like Python all that much but it’s comprehensions and generators are very sweet.

Re:Why I'm still using Python by Kwpolska on Saturday December 31, 2022 @07:09AM (#34195739)
I find the non-Python versions easier to read, since they show the exact data flow in order (instead of Python’s [3 for 1 if 2] order) and they allow more advanced scenarios.
Re:Why I'm still using Python by atoav on Saturday December 31, 2022 @04:12AM (#34194854)
Sure you can do that and I use things like this all the time in other languages, but the python example was very basic. There are other cases that are sometimes harder to reproduce e.g. when iterating over dictionaries to create a list, when you have tuples etc.
Re:Why I'm still using Python by matsemann on Saturday December 31, 2022 @05:04AM (#34195099)
It's the opposite, I feel. When the cases are not basic, the python way gets even messier. Or do you have any examples?
Re:Why I'm still using Python by Kwpolska on Saturday December 31, 2022 @07:30AM (#34195871)
All Python list comprehensions do is [(expression involving foo's) for foo0, …, fooN in (iterable) if (expression involving foo's that should return a boolean-ish value)]. Nothing more, nothing less. Nothing that can’t be expressed by filter-then-map.

So, given the dictionary {"a": 1, "b": 4, "c": 2}, if you want ["b=4", "c=2"], you can do this in Python:

    d = {"a": 1, "b": 4, "c": 2}
    l = [f"{k}={v}" for k, v in d.items() if v % 2 == 0] # replace [] with () if you want a generator instead of a list
Or this in C#:

    var d = new Dictionary<string, int> { {"a", 1}, {"b", 4}, {"c", 2} };
    var l = d
             .Where(pair => pair.Value % 2 == 0)
             .Select(pair => $"{pair.Key}={pair.Value}")
             .ToList(); // remove this if you want an IEnumerable<string> instead of a List<string>
The Python version has tuple unpacking, whereas the C# version iterates over KeyValuePair<TKey,TValue>. Slightly more typing, and perhaps slightly less ideal if you’re dealing with tuples without field names, but still pretty readable. The C# solution is also more obvious about the execution order.

And if you want to sort the output by the dictionary value?

    l = [f"{k}={v}" for k, v in sorted(d.items(), key=lambda kv: kv[1]) if v % 2 == 0]
    #    5              3       2      1              2a                   4           <- Execution order

    var l = d                                             // Execution order: 1
             .OrderBy(pair => pair.Value)                 //                  2
             .Where(pair => pair.Value % 2 == 0)          //                  3
             .Select(pair => $"{pair.Key}={pair.Value}")  //                  4
             .ToList();                                   //                  5
Re:Why I'm still using Python by gdprrrr on Saturday December 31, 2022 @04:27AM (#34194924)
Have you tried Haskell vor Scala?
Re:Why I'm still using Python by mmcnl on Saturday December 31, 2022 @12:40PM (#34198681)
I love list comprehensions but my brain starts melding with nested list comprehensions. The syntax is not obvious and I have to Google it and figure it out again 100% of the time. The JavaScript .map() method is much easier to understand.
Re:Why I'm still using Python by type-r on Saturday December 31, 2022 @09:30PM (#34202988)
I like list comprehensions now after having used the language for a while, but I will say they were the hardest for me to grok when I was first learning the language. even now it can be difficult to follow what's going on if you have nested ones.
Re:Why I'm still using Python by msz-g-w on Sunday January 01, 2023 @06:09AM (#34205412)
> Downsides? Dependency managment, tooling, speed

What's wrong with its tooling?