When making a UI there are a lot of binding/trace operations that need
to occur that lead to a lot of annoying 1 use function definitions. I
don't really see lambda use like below.
Giving 2 working lambda examples using a returned tuple to accomplish >multiple expressions - what sort of gotchas, if any, might make the
following bad practice if I am missing something?
b = tk.Button(master=main, text="Enable")
b.config(
   command=lambda: (
       e1.config(state="normal"),
       e2.config(state="normal"),
       e3.config(state="normal")
   )
)
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)
In both cases (as per my intent)
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))
When making a UI there are a lot of binding/trace operations that need
to occur that lead to a lot of annoying 1 use function definitions. I
don't really see lambda use like below.
Giving 2 working lambda examples using a returned tuple to accomplish multiple expressions - what sort of gotchas, if any, might make the
following bad practice if I am missing something?
b = tk.Button(master=main, text="Enable")
b.config(
command=lambda: (
e1.config(state="normal"),
e2.config(state="normal"),
e3.config(state="normal")
)
)
When making a UI there are a lot of binding/trace operations that need
to occur that lead to a lot of annoying 1 use function definitions. I
don't really see lambda use like below.
Giving 2 working lambda examples using a returned tuple to accomplish multiple expressions - what sort of gotchas, if any, might make the
following bad practice if I am missing something?
I finally realized why I am uncomfortable with doing this kind of thing.
It's because, IMHO, lambda expressions should not have side effects
The 'what I am trying to do' is ask a question regarding opinions and practices on issuing a sequence of actions within a lambda via a tuple
(since the common practice approaches against it - mainly with tkinter -
feel more convoluted), and in doing so leaving it open ended to get a
feel on what opinions are, and to see if any opinions influence mine.
# this is a code snippet from a Tkinter gui app
# in this case lambda is quite convenient
self.btn_cancel = Button(self.progress_container, text='Cancel',
command=lambda: subprocess.call('taskkill /f /im uberzip.exe',
shell=True))
Also layout is all important here. It could get very messy to read if >indentation isn't clear. You only have to look at some Javascript code
with function definitions as arguments to functions to see how clunky
that can be.
On 08/03/2023 21:56, aapost wrote:
When making a UI there are a lot of binding/trace operations that need
to occur that lead to a lot of annoying 1 use function definitions. I
don't really see lambda use like below.
Lambdas are very common in GUI callbacks but I admit I've never seen
tuples used to create multiple expressions. That's a neat trick I
hadn't thought of and will probably use.
On 3/9/2023 3:29 AM, aapost wrote:
The 'what I am trying to do' is ask a question regarding opinions and practices on issuing a sequence of actions within a lambda via a tuple (since the common practice approaches against it - mainly with tkinter - feel more convoluted), and in doing so leaving it open ended to get a
feel on what opinions are, and to see if any opinions influence mine.
I finally realized why I am uncomfortable with doing this kind of thing.
It's because, IMHO, lambda expressions should not have side effects
and should not require much mental effort to grasp what they do. Yes,
you can do so. You can even print from a lambda (and it might be useful
for debugging):
lambda x: print(f'The lambda received {x}') or x*x
The Python Reference on readthedocs.io also has a tk example that specifically wants the side effect (see https://python-reference.readthedocs.io/en/latest/docs/operators/lambda.html):
# this is a code snippet from a Tkinter gui app
# in this case lambda is quite convenient
self.btn_cancel = Button(self.progress_container, text='Cancel',
command=lambda: subprocess.call('taskkill /f /im uberzip.exe',
shell=True))
Maybe so, but I think it's better not to have side effects hidden away
in expressions that are hard to read and understand. And being
anonymous, there is no function name to remind you what the action is
suppose to do. Much better (still IMHO, of course):
def kill_uberzip():
"""Kill an external running program named uberzip.exe."""
subprocess.call('taskkill /f /im uberzip.exe', shell=True))
self.btn_cancel = Button(self.progress_container, text='Cancel',
command = kill_uberzip())
This way, it's easy to understand what btn_cancel() will do each time
you scan that line of code.
For this particular example, it might turn out that there could be more
than one instance of uberzip.exe running at the same time. Which one
should be killed, and how do you kill the right one? With the function,
you can get those details under control, but I hate to think what might happen to the lambda expression.
Yes, of course, there can be times when the lambda expression is
somewhat easy to understand and the side effects are harmless. In that
case, it may be easy enough to grasp quickly that the anonymous function would not benefit from having a name. So OK, it's not a hard-and-fast
rule.
On 09Mar2023 09:06, Alan Gauld <learn2program@gmail.com> wrote:
Just a note that some code formatters use a trailing comma on the last element to make the commas fold points. Both yapf (my preference) and
black let you write a line like (and, indeed, flatten if short enough):
   ( a, b, c )
but if you write:
   ( a, b, c, )
they'll fold the lines like:
   ( a,
     b,
     c,
   )
Cameron Simpson <cs@cskk.id.au>
On 3/9/23 16:37, Cameron Simpson wrote:
Just a note that some code formatters use a trailing comma on the last >>element to make the commas fold points. Both yapf (my preference) and
black let you write a line like (and, indeed, flatten if short
enough):
   ( a, b, c )
but if you write:
   ( a, b, c, )
they'll fold the lines like:
   ( a,
     b,
     c,
   )
Cameron Simpson <cs@cskk.id.au>
Thanks for the info, good to know, I actually do like the idea of
trailing commas for tuples (helps prevent things like the difference
between ("abc") and ("abc",) and makes swapping things around nicer.
I've just been using a lot of json lately and it has been
subconsciously training me different, lol.
# this is a code snippet from a Tkinter gui app
# in this case lambda is quite convenient
self.btn_cancel = Button(self.progress_container, text='Cancel',
    command=lambda: subprocess.call('taskkill /f /im uberzip.exe',
    shell=True))
def kill_uberzip():
   """Kill an external running program named uberzip.exe."""
   subprocess.call('taskkill /f /im uberzip.exe', shell=True))
self.btn_cancel = Button(self.progress_container, text='Cancel',
    command = kill_uberzip())
This way, it's easy to understand what btn_cancel() will do each time
you scan that line of code. Using the lambda makes you reparse the line
and spend mental effort each time you scan it. And this way, you know directly that the button is going to cause a side effect outside your program, which you have to infer (an indirect mental operation) when you
scan the lambda.
For this particular example, it might turn out that there could be more
than one instance of uberzip.exe running at the same time. Which one
should be killed, and how do you kill the right one? With the function,
you can get those details under control, but I hate to think what might happen to the lambda expression.
Yes, of course, there can be times when the lambda expression is
somewhat easy to understand and the side effects are harmless. In that case, it may be easy enough to grasp quickly that the anonymous function would not benefit from having a name. So OK, it's not a hard-and-fast
rule.
       main.pids.update({"messages" :subprocess.Popen(["tail", "-n", "1", "-f", "/var/log/messages"])}),
       main.pids.update({"syslog" :subprocess.Popen(["tail", "-n", "1", "-f", "/var/log/syslog"])}),
       main.pids.update({"kern" :subprocess.Popen(["tail", "-n", "1",
"-f", "/var/log/kern.log"])}),
       main.pids.update({"user" :subprocess.Popen(["tail", "-n", "1",
"-f", "/var/log/user.log"])}),
    ),
On 2023-03-10 at 22:16:05 -0500,
Thomas Passin <list1@tompassin.net> wrote:
I'd make the pattern in this example even more understandable and less
error-prone:
def update_pids(target):
cmd = ["tail", "-n", "1", "-f", f"/var/log/{target}"]
pids.update({target: subprocess.Popen(cmd)}) if not \
pids[target] else None
I might be missing something, but how is that more understandable and
less error prone than any of the following:
if not pids[target]:I only continued the line for the purposes of the post because it would
cmd = ["tail", "-n", "1", "-f", f"/var/log/{target}"]
pids.update({target: subprocess.Popen(cmd)})
or:
cmd = ["tail", "-n", "1", "-f", f"/var/log/{target}"]
pids[target] or pids.update({target: subprocess.Popen(cmd)})
or:
if pids[target]:
pass
else:
cmd = ["tail", "-n", "1", "-f", f"/var/log/{target}"]
pids.update({target: subprocess.Popen(cmd)})
Picking a nit, that's not a good place to continue that line with the backslash, either.
IMO, "not pids[target]" should be atomic.
I'd make the pattern in this example even more understandable and less error-prone:
def update_pids(target):
cmd = ["tail", "-n", "1", "-f", f"/var/log/{target}"]
pids.update({target: subprocess.Popen(cmd)}) if not \
pids[target] else None
which does start to break down readability due to line length, as there
isn't really an indention rule set for something uncommonly used.
but some renaming makes the pattern clearer
pids.update({"messages" :subprocess.Popen(["cmd1"])}) if not
pids["messages"] else None,
pids.update({"syslog" :subprocess.Popen(["cmd2"])}) if not
pids["syslog"] else None,
pids.update({"kern" :subprocess.Popen(["cmd3"])}) if not pids["kern"]
else None,
pids.update({"user" :subprocess.Popen(["cmd4"])}) if not pids["user"]
else None,
On 3/10/2023 7:07 PM, aapost wrote:
which does start to break down readability due to line length, as
there isn't really an indention rule set for something uncommonly used.
but some renaming makes the pattern clearer
pids.update({"messages" :subprocess.Popen(["cmd1"])}) if not
pids["messages"] else None,
pids.update({"syslog" :subprocess.Popen(["cmd2"])}) if not
pids["syslog"] else None,
pids.update({"kern" :subprocess.Popen(["cmd3"])}) if not pids["kern"]
else None,
pids.update({"user" :subprocess.Popen(["cmd4"])}) if not pids["user"]
else None,
I'd make the pattern in this example even more understandable and less error-prone:
def update_pids(target):
   cmd = ["tail", "-n", "1", "-f", f"/var/log/{target}"]
   pids.update({target: subprocess.Popen(cmd)}) if not \
       pids[target] else None
lambda x: ( # The Tk callback includes an event arg, doesn't it?
           update_pids('messages'),
           update_pids('syslog'),
           # etc
         )
On 3/10/23 22:16, Thomas Passin wrote:[...]
The additional note in the above is, when taking the def route above,
the thing you would have to consider is what scope is the dictionary pids?
Do you need to submit it to the lambda and subsequently the function
such as
lambda pids=pids: (
   update_pids("messages", pids),
   update_pids("syslog", pids),
So that update_pids can access it? Or in your design do you have a
separate management of it that def update_pids already has access to?
(either is valid depending on design intent).
xxxdef printme(x): print(x) # Let's not quibble about inline defs!
printme('xxx')
... printme('this'),cmd = lambda x: (
thiscmd(2)
thiscmd(2)
... printme('this'),def printme(x): print(y) # Print some other variable, not "x"
y = 'I am y' # Will "y" get passed through into the lambda?
cmd = lambda x: (
I am ycmd(2)
I am a post-compile assignmenty = 'I am a post-compile assignment'
cmd(2)
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 546 |
Nodes: | 16 (2 / 14) |
Uptime: | 13:01:38 |
Calls: | 10,389 |
Calls today: | 4 |
Files: | 14,061 |
Messages: | 6,416,887 |
Posted today: | 1 |