On 3/27/2019 4:21 AM, Alexey Muranov wrote:
Whey you need a simple function in Python, there is a choice between a normal function declaration and an assignment of a anonymous function (defined by a lambda-expression) to a variable:

    def f(x): return x*x

or

    f = lambda x: x*x

PEP 8 properly recommends against this the latter as functionally it has no advantage and the disadvantage that f.__name__ becomes the generic '<lambda>' instead of the specific 'f'. This is not useful for code that expects specific names. Tracebacks are one example. Here is another intended to list callable objects and their types.

def call_clas(container):
    for item in vars(container).values():
        if hasattr(item, '__call__'):
            yield item.__name__, item.__class__

def print_cc(container):
    for name, clas in call_clas(container):
        print(f'{name:30s}{clas}')

# Examples.
print_cc(int)
from idlelib import pyshell
print_cc(pyshell)

Multiple output lines of '<lambda> function' defeat the purpose.

So my opinion is that lambda expressions should only be used within larger expressions and never directly bound.

It would be however more convenient to be able to write instead just

    f(x) = x*x

Given my view above, this is, standing alone, strictly an abbreviation of the equivalent def statement. I am presuming that a proper implementation would result in f.__name__ == 'f'.

Is the convenience and (very low) frequency of applicability worth the inconvenience of confusing the meaning of '=' and complicating the implementation?

I do not see any conflicts with the existing syntax.

It heavily conflicts with existing syntax.  The current meaning of
  target_expression = object_expression
is
1. Evaluate object_expression in the existing namespace to an object, prior to any new bindings and independent of the target_expression. 2. Evaluate target_expression in the existing namespace to one or more targets.
3. Bind object to target or iterate target to bind to multiple targets.

Part of step 2 is making calls, because calls cannot be targets. This is why 'f(a+b)[c] = d' can work. Note that 'a+b' makes calls to a.__add__ or b.__radd__ or both.

In the proposal, the treatment of the object expression would depend on the target expression and the alternative would be to quote it as code; compile the code in a manner that depends on the target expression to mark local names versus global names; and finally make a function instance, presumably taking __name__ from the target.

This would have the advantage over lambda assignment of getting the name right, but I don't think one should be doing lambda assignment anyway. There is a good reason to have a separate syntax.

Before 3.8, I would stop here and say no to the proposal. But we now have assignment expressions in addition to assignment statements.

>>> int(s:='42'+'742')
42742
>>> s
'42742'

To me, function assignment expressions, as a enhanced replacement for lambda expressions, is more inviting than function assignment statements as an abbreviation for function definition statements.

In other words, replace

  map(lambda x: x*x, range(10))

with

  map(square(x):=x*x, range(10))

or, if one does not want a specific name,

  map(_(x):=x*x, range(10))

Many people dislike lambda expressions, to the point that Guido considered leaving them out of 3.x. So this replacement might get more traction. It would make assignment expressions much more useful.

--
Terry Jan Reedy


--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to