Our ListFrame class has only two methods to interact with the inner list: pop_selection() and insert_item(). The first one returns and deletes the current selection, or none if there is no item selected, whereas the second one inserts a new item at the end of the list.
These methods are used in the parent class to transfer an item from one list to the other one:
def move(self, frame_from, frame_to):
value = frame_from.pop_selection()
if value:
frame_to.insert_item(value)
We also took advantage of the parent frame containers to correctly pack them with the appropriate padding:
# ...
self.frame_a.pack(side=tk.LEFT, padx=10, pady=10)
self.frame_b.pack(side=tk.RIGHT, padx=10, pady=10)
Thanks to these frames, our calls to the geometry manager are more isolated and organized in our global layout.