Though to be fair, having explicit intermediate variables is idiomatic in Python, from what I've seen. It's one of my biggest pet-peeves about the language, but it's not without precedent.
It's not being reused and one of the following is true... I don't want to leave behind intermediary objects for whatever reason is relevant, or I feel its worth it to compress the logic to make it possible to use a language feature that requires an expression, like lambdas or list/dict comprehensions.
Lets make this a somewhat concrete example.
---
heights = [1,2,3]
widths = [4,5,6]
# printing area greater than 10
# functional
heights.zip(widths).map(to_area).filter(lambda area: area > 10).forall(lambda a: print("Area " + a)
#Verbose way
hw_zipped = zip(a,b)
areas = hw_zipped.map(to_inches)
big_areas = areas.filter(a: a > 10)
for a in big_areas: print("Area " + a)
---
Which do you prefer? I would argue the right level of abstraction is the functional way in this example, and its often the case in my experience, especially in python where you don't often use a namespace to store these intermediary variables and you have can't rely on typing
result = [area for x,y in zip(heights,widths) if (area := to_area(x,y)) > 10]
I don't think that's very easy to read; I'd opt for two list comps like areas = [to_area(x,y) for x,y in zip(heights,widths)]
result = [area for area in areas if area > 10]
But I agree with OP that map+filter is easier to read.In scala:
---
val widths = Seq(1,2,3)
val heights = Seq(4,5,6)
widths.zip(heights).foreach { case (w, h) => {
val area = w * h
if (area > 10) {
println(s"Area: ${area}")
}
}}println(area) // error: not found: value area
[area for area in (to_area(x, y) for x, y in zip(h, w)) if area > 10]
or generally, you can take a multiline statement like the one you have and replace named value with its expression. Add some indentation and it's not too bad: [area for area in
(to_area(x, y) for x, y in zip(h, w))
if area > 10] for x, y in zip(a,b):
area = to_area(x, y)
if area > 10:
print(f"Area {area}")
>in python where you don't often use a namespace to store these intermediary variablesHm? Most python code is within a function, in my experience.
If its not in a function, your example may (or may not depending on length if either a or b have a length of zero) create a floating variable called area out there.
arr.map(func)
vs. list(map(func, arr))Working with data scientists, in practice, these identifiers are usually "arr1", "arr2", &c. I'd rather have method chaining. Often the intermediates are not meaningful.
It's probably the core skill of good programmers though, so it should be taught more. I don't think anyone sets out to use misleading names, but it's easy for name and code to diverge, and it's crippling to readability.
However, often when refactoring/updating such data scientist code (or even understanding), I need to break apart the long method chains, and this is much, much more annoying than dealing with crummy names.
At least I can print the values associated with the names, which is not easily possible in the really long method chain.
I find fluent style often clearer as well as more terse than with superfluous intermediate variables. Verbosity isn't the same thing as clarity.
(But in Python, comprehensions/genexps are often clearer than either.)
The idiomatic Python 3 version uses generators to compose the computation and to avoid unnecessary memory allocations. Does funct.Array also do this?
- https://docs.python.org/3/library/functions.html#map - https://docs.python.org/3/library/functions.html#filter
> all(func3(a) for h,w in zip(a,b) for a in func1(h,w) if func2(a))
> all(map(func3, filter(func2, map(func1, zip(a, b)))))
> a.zip(b).map(func1).filter(func2).forall(func3)
The original is indeed terrible and the second version is a bit better. A lot better than either one, though, is splitting your logic into multiple lines and assigning a descriptive identifier to each step. Maybe even throw in some inline comments if you're particularly respectful of others' time.
As tempting as it is to do something super clever and cram a ton of functionality into a small number of lines or characters (it does feel good), it's just better to be a bit more verbose and write simple, obvious code. I feel like code should be read like a book, not a puzzle.