For my application GUI (tkinter), I need a 'bookkeeping' variable that holds the current row number for a UI widget. I prefer not to hard code the row number because inserting a widget would involve renumbering all row numbers following it. In this situation, an increment operator (x++
, similar to C++) would come in very handy, because incrementing the variable when necessary would require only two additional characters. However, Python does not support increment operators.
To avoid increment statement between elements that should go on different rows, I came up with the following solution but I am wondering what an alternative might be:
rownums = list(range(100))
rowstay = lambda: rownums[0] # Return current row number and stay on row.
rowmove = lambda: rownums.pop(0) # Return current row number and move on to next.
print(f'Two items: {rowstay()}, {rowmove()}')
print(f'One item: {rowmove()}')
print(f'Two items: {rowstay()}, {rowmove()}')
For example (tkinter):
# Create some buttons.
mybutton1 = tkinter.button(master, 'Button on row 0')
mybutton2 = tkinter.button(master, 'Button on row 0')
mybutton3 = tkinter.button(master, 'Button on row 1')
# Place buttons (use mimicked increment 'operator').
mybutton1.grid(row=rowstay(), column=0)
mybutton2.grid(row=rowmove(), column=1)
mybutton3.grid(row=rowmove(), column=0)
What alternative code would provide the same functionality?
From the comments and answer, I learned that mutating with a lambda and assigning lambdas is not Pythonic. Several comments suggest using += 1
but this is exactly what I wanted to avoid because it requires an additional statement for each time the variable should be incremented. The solution with higher order functions (or a class) mimics ++x
instead of x++
.
My solution (second-best, see better solution under EDIT):
class BookkeepingVar():
""" Variable with the ++-operator from C++ mimicked.
Example:
x = BookkeepingVar(0)
y = x() + 1 # y = 1, x = 1
z = x(1) + 1 # z = 1, x = 2
"""
def __init__(self, start=0):
self.var = [start]
def __call__(self, incr=0):
if incr:
self.var.append(self.var[0] + incr)
return self.var.pop(0)
else:
return self.var[0]
Example usage:
# Create some buttons.
mybutton1 = tkinter.button(master, 'Button on row 0')
mybutton2 = tkinter.button(master, 'Button on row 0')
mybutton3 = tkinter.button(master, 'Button on row 1')
# Place buttons.
row = BookkeepingVar(0)
mybutton1.grid(row=row(0), column=0)
mybutton2.grid(row=row(1), column=1)
mybutton3.grid(row=row(1), column=0)
Please note:
pop()
to be problematic.x++
only because it also supports increments other than 1. __call__
method was implemented in order to make notation as short as possible.EDIT:
A simpler and more elegant solution without list (same usage):
class BookkeepingVar():
""" Variable with the ++-operator from C++ mimicked.
Example:
x = BookkeepingVar(0)
y = x() + 1 # y = 1, x = 1
z = x(1) + 1 # z = 1, x = 2
"""
def __init__(self, start=0):
self.var = start
def __call__(self, incr=0):
self.var += incr
return self.var - incr
EDIT 2:
Remark about ++x
vs. x++
(strikethrough).
Given you apparently don't use things like rowspan, I'd have the custom object be in charge of the entire thing and call
grid
internally e.g.layout = Layout(); layout.row(mybutton1, mybutton2); layout.row(mybutton3)
. Andlayout
could keep track of the current row using either a regular integer or anitertools.count()
. Obviously if you're using a more complex layout than just a bunch of rows that doesn't work. Though you could probably have something even more declarative.