[Python-ideas] Explicit variable capture list
Terry Reedy
tjreedy at udel.edu
Tue Feb 16 16:07:34 EST 2016
On 1/25/2016 1:52 PM, Guido van Rossum wrote:
> On Sun, Jan 24, 2016 at 10:32 PM, Terry Reedy <tjreedy at udel.edu> wrote:
>> What I've concluded from this thread is that function definitions (with
>> direct use 'def' or 'lambda') do not fit well within loops, though I used
>> them there myself.
>
> Right. When you can avoid them, you avoid extra work in an inner loop,
> which is often a good idea.
>
>> When delayed function calls are are needed, what belongs within loops is
>> packaging of a pre-defined function with one or more arguments within a
>> callable. Instance.method is an elegant syntax for doing so.
>> functools.partial(func, args, ...) is a much clumsier generalized
>> expression, which requires an import. Note that 'partial' returns a
>> function for delayed execution even when a complete, not partial, set of
>> arguments is passed.
>
> Right. I've always hated partial() (which is why it's not a builtin)
> because usually a lambda is clearer (it's difficult to calculate in
> your head the signature of the thing it returns from the arguments
> passed), but this is one thing where partial() wins, since it captures
> values.
I agree that the difficulty of immediately grokking the signature
partials that binds arbitrary parameters is a downside to their use.
Fake parameters set to a constant necessarily go at the end of the
parameter list. The actual signature is the list with those parameters
chopped off and ignored. To eliminate the possibility of accidentally
supplying a different value positionally, such parameters could (and I
think should) be made keyword-only.
def f(a, b='default', *, int=int): pass
Bound methods necessarily bind the first parameter, often called 'self'.
This again makes the actual signature easy to determine.
>> A major attempted (and tempting) use for definitions within a loop is
>> multiple callbacks for multiple gui widgets, where delayed execution is
>> needed. The three answers to multiple 'why doesn't this work' on both
>> python-list and Stackoverflow are multiple definitions with variant 'default
>> args', a custom make_function function outside the loop called multiple
>> times within the loop, and a direct function outside the loop called with
>> partial within the loop. I am going to start using partial more.
Since writing this, I realized that defining a custom class and using
bound methods is a fourth option, which I also like. This binds the
differentiating data to an instance, which is then bound to the
function, rather than to the function directly. A toy example:
----
import tkinter as tk
root = tk.Tk()
class Card(tk.Button):
hide = 'XXX'
def __init__(self, txt):
tk.Button.__init__(self, root, text=self.hide) # or
# super().__init__(root, text=self.hide)
self.txt = txt
self.exposed = False
def flip(self):
self['text'] = self.hide if self.exposed else self.txt
self.exposed = not self.exposed
for i, txt in enumerate(('one', 'two')):
card = Card(txt)
card['command'] = card.flip
card.grid(row=0, column=i)
#root.mainloop() # uncomment if run on command line without -i
----
The main problem with this is that some beginners are trying to write
(or being told to write) tkinter guis before they learn about class
statements. The super() form is easier to write, but its use is even
more 'advanced'.
--
Terry Jan Reedy
More information about the Python-ideas
mailing list