I am new to python. I have a few questions coming from an armature!

Steven D'Aprano steve+comp.lang.python at pearwood.info
Thu Aug 18 05:32:37 EDT 2016


On Thursday 18 August 2016 06:25, Terry Reedy wrote:

> On 8/17/2016 2:07 AM, Steven D'Aprano wrote:
> 
>> I realise that there are occasions where we might deliberate choose to
>> assign an intermediate value to its own variable, but all else being equal,
>> which would you prefer?
>>
>> #A
>> alist = []
>> alist.append(2)
>> alist.append(4)
>> alist.append(8)
>> process(alist)
[... snip additional examples ...]

> Up to here, #A is a useless and stupid.  Have you seen such code written?

As a matter of fact, yes.

Just the other day I posted an example from a former work-mate that was *worse* 
than any of those, something like this:

x = []
x.append(1)
x = len(x)



>> #A
>> def callback(btn):
>>     return btn.do_the_thing(42) or default
>> the_button.setcommand(callback)
>> process(the_button)
>>
>> #B
>> the_button.setcommand(lambda btn: btn.do_the_thing(42) or default)
>> process(the_button)
> 
> This example is *not* parallel to the other 3.  Here, A is useful real
> code and might be preferred for multiple reasons.

Sure -- I acknowledged at the beginning that there may be reasons why you want 
to give an intermediate value its own variable name.


>> If you find yourself preferring B, B, B, A, you might ask yourself what
>> makes a function different that you prefer to keep temporary functions
>> around where they're not needed.
> 
> When 'callback' is set as the command of the button, it is not
> temporary, but must remain as long as the button remains.  Only the name
> binding is (possibly) disposable.

The name binding is certainly disposable, because if it wasn't, you couldn't 
use an anonymous function (a lambda). *In general*, keeping an additional named 
reference to the callback around is unnecessary and wasteful -- although, as 
you point out and as I acknowledged, there may be exceptions.


> Beginners often do not understand that the body of a lambda expression
> is evaluated in a new local namespace, and only when the resulting
> function is called, the same as with a def statement.  They then neglect
> to capture current values when writing lambda expressions in a for loop.

Sure. But since the behaviour of def functions and lambda functions are 
identical, writing a named def won't solve that problem.


>          for section_name, line_number in text.parser.toc:
>              def goto(line=line_number):
>                  text.yview(line)
>              drop.add_command(label=section_name, command=goto)
> 
> To me, this is much better and I intend to commit it.  Thank you for
> prodding me to think through how bad the lambda form can be and to
> rewrite the loop so I don't cringe reading it.

The use of a named function here adds next to nothing. Instead of some number 
of anonymous functions called "<lambda>", you have an equal number of functions 
all named "goto". There's no easy way to distinguish them, and likely no real 
need to distinguish them -- they are simple enough that you can be almost 
certain that they are correct just from reading the code. So I don't see any 
benefit over this:

         for section_name, line_number in text.parser.toc:
             drop.add_command(label=section_name, command=lambda
                              line=line_number: text.yview(line))

except that it is easier to fit in 79 columns :-)


-- 
Steve




More information about the Python-list mailing list