Lambda returning tuple question, multi-expression

aapost aapost at idontexist.club
Wed Mar 8 23:19:51 EST 2023


On 3/8/23 16:56, aapost wrote:
> Thomas > Cameron

> def set_entries_enabled_state(enabled = True):
>      state = 'normal' if enabled else 'disabled'
>      for e in (e1, e2, e3):
>          e.config(state=state)
> 
> def config_b_and_entries(enabled = True):
>      state = 'normal' if enabled else 'disabled'
>      b.config(state = state)
>      set_entries_enabled_state(enabled)

I admit adding commenting might be useful to clearly express intent for 
patterns I don't commonly see. But when you are managing a bunch of 
widgets and experimenting with the design, the variable name word salad 
approach 'in the name of readability' starts to melt your brain a bit 
and it all starts too look like a wall of..:

the_thing.the_things_thing.do_this_thing_to_that_other_thing_but_only_if_this_one_time()

So the button b in the example only needs a reference to a callable 
configured, set with the command= parameter in .config()

The code:

def func():
   pass
b.config(command=func)

Is equivalent. So that if the button is clicked, code at func (or the 
lambda) gets called.

In both cases (as per my intent), care about the return values of the 
expressions does not matter and I am fairly certain regardless of what 
the callable returns, it does not get evaluated/assigned/considered 
anywhere. (at least that is how I have been considering it, a void 
foo(void) if you will..). Now as far as the tuple, yes, left to right 
evaluation is what I expect, (hope anyway, lol),

meaning (3, False, 1, x := 5+9, print("hello{}".format(x)))
would return a tuple of (3, False, 1, 14, None) which gets assigned to 
nothing and the string "hello14" printed to console.

Now.. When you want to assign a callable that requires args, the main 
examples people give are a combo of them both,

def func(x,y,z):
   pass
x = y = x = "something"
b.config(command=lambda x,y,z: func(x,y,z))

So as far as the examples given above (which I can't really parse), if 
you meant for passing in a bool value, to do so would require something 
like:

b.config(command=lambda enabled: config_b_and_entries(enabled))

Which that type of thing to me gets even harder to grok after a while, 
and I guess for me I find having to go to a different scope or a 
separate file to parse a bunch of definitions like these:

def set_entries_enabled_state(enabled = True):

def config_b_and_entries(enabled = True):

ends up taking me out of an object oriented focus / headspace of the 
layout at hand.


And it is sort of like.. Ok I can either

b.config(command=lambda: (
     a.expr,
     b.expr.update({something: "morecomplicated"}),
     c.expr
     )
)

OR..

b.config(command=lambda a=a, b=b, c=c, s=something: foo(a, b, c, s))

somewhere else:
def foo(a, b, c, something):
     a.expr
     b.expr.update({something: "morecomplicated"})
     c.expr


When you are trying to add a bit of dynamic feel to the tediousness of 
the widget management, keeping things kind of contained to their object 
just feels more natural to me (at the moment anyway).. (all the packing, 
unpacking, making collections of widgets within frames appear or go away 
based on states, colour changes based on input, dynamic widget 
generation and where their relative attachment should go, etc)

I read a lot of sentiment against complicated lambdas suggesting one 
should go for more functions, but I guess I feel pushing a more 
complicated lambda to contain behavior more closely to an instance feels 
more intuitive at the moment (and the sentiment against it doesn't 
really resonate with me), so long as it isn't introducing some inherent 
behavioral flaw or bug I am blind to..

Of course I might change my mind at some point during a refactor and 
think "what the hell is that, why didn't I just..".. Which will probably 
come in a few weeks. lol

One additional note on the Thread comment, I haven't really needed to 
dig in to that too deeply, but Threading is amazing for tkinter UI 
troubleshooting,

if you add something like:
t = threading.Thread(target=maintk.mainloop)
and run it with python -i
so long has you have attached every widget to some relative position on 
to the root (maintk in this case), you can interact with any 
object/widget directly live to see what is going on or what a change does.



More information about the Python-list mailing list