Hacker News new | ask | show | jobs
by kazinator 2586 days ago
Since Python lambdas also are expressions, they cannot contain statements, due to Python adhering to the Algol-like statement/expression syntactic paradigm. If a lambda expression could contain statements, that would mean that almost any other kind of Python expression could also contain statements by containing a lambda expression.

But, here above, I'm writing more from the angle of supporting multi-line lambdas that contain statements. Strictly speaking, you are only bemoaning the lack of multiple expression support, not multi-line lambdas.

Python could adopt something similar to the C comma operator. It almost has that in the form of list constructors, except that these return a list, instead of the rightmost value:

  [foo(), bar(), xyzzy()] #   foo, bar and xyzzy are called
Idea: a dummy function called progn could be used for this:

  >>> def progn(*rest):
  ...    if len(rest) > 0:
  ...       return rest[-1]
  ...    return None
  ... 
  >>> progn(1, 2, 3)
  3
  >>> progn(1)
  1
  >>> progn()
So now we can do:

  >>> x = lambda arg: progn(print(arg), print(arg), "done")
  >>> x(42)
  42
  42
  "done"
  >>>
There you go. Lambdas are (effectively) not limited to a single expression. If progn is too long, call it pg (Paul Graham) or pn (Peter Norvig).

Always have your Lisp hat on, even if you find yourself in Python land.

Maybe this is a common trick? I don't use Python; I hardly know anything about it. I wrote one Python program before which garbage-collects unreferenced files from a Linux "initramfs" image, making it smaller (thus reducing a kernel image size). This was in a Yocto environment, which is written in Python 3, so that choice of language made sense.

BTW does Python require left-to-right evaluation order for arguments? I would sure hope so; it would probably be "un-Pythonic" to plant such a bomb into the language as unspecified eval order.

BTW looks like a more idiomatic definition for progn is:

  >>> def progn(*rest):
  ...    return None if len(rest) == 0 else rest[-1]
2 comments

> Maybe this is a common trick?

No. It's obvious and trivial, but you'd be on a verge of being called names if you tried to use it in a Python codebase. Lambdas in Python are limited to a single expression by convention - which in Python-land is scarily rigid and specific - rather than just by the language spec.

Before `... if ... else ...` was added to the language as an expression (I think around 2.5), people had to make do with some workarounds. The fact that `True` and `False` get automatically casted to ints and back allowed for writing something like `[val_if_false, val_if_true][condition]`. Or you could use `and`/`or` combination as per usual. The official stance at the time was to never do this and use an `if` statement instead, but people still sometimes resorted to it. Then, the `if` expression was introduced specifically to combat the use of such workarounds. Now you'd be lynched if you tried to use one of them.

"There should be one - and preferably only one - obvious way to do it" - from the Zen of Python[1].

In general, despite a lot of effort to eliminate them, there are still some creative ways to use the language. It will always be the case, obviously, as you demonstrate. However, that creativity is 100% rejected by the community, to the point that even mentioning inadequacy of some construct for some use case is frowned upon - because it could lead to people inventing creative workarounds. If you try to complain about something in the language, the general attitude is "write a PEP or GTFO". More often than not it results in the latter.

The saddest part of it all is that this apparently is one of the major factors that made Python as popular as it is. There are valid reasons and a lot of advantages to this strategy. Go is similar as far as I can tell. Among the dynamic languages with rich syntax, Python codebases tend to be stylistically very close to each other, and not because there is a lack of ways this rich syntax could be (ab)used, but because doing so is unpythonic.

Haaah, now I said it... I hope not many Python programmers read this thread; I can already see torches and pitchforks on the horizon...

Source: I've been writing Python for the last 12 years for pay.

[1] https://en.wikipedia.org/wiki/Zen_of_Python

My experience with Go is that the syntax is more rigid as compared to Python but the community is much less idealistic.

As long as your code is linted with gofmt and it compiles (and doesn’t abuse reflection), the community tolerates more creative uses of the syntax to get around some of the pitfalls of the language – but there is of course less opportunity for creative syntax than in a dynamic language like Python.

>Strictly speaking, you are only bemoaning the lack of multiple expression support, not multi-line lambdas.

Oh, I'm not bemoaning. I'm just answering GP about the likely limitations that the previous poster was complaining about.

>Maybe this is a common trick? I don't use Python; I hardly know anything about it.

I work around lambdas by naming internal functions. It's easier to read intent if I tell you what I'm trying to do.