5
\$\begingroup\$

The REPL offers functionality for inserting, deleting, and searching within a red-black tree, along with the capability to generate an ASCII or graphical representation of the tree structure.

#!/usr/bin/env python3
import sys
from plot import plot_tree
from rbtree import RedBlackTree
COMMANDS = {
 "insert": lambda rbt, x: rbt.insert(x),
 "delete": lambda rbt, x: rbt.delete(x),
 "search": lambda rbt, x: print(rbt.search(x).get_key()),
 "print": lambda rbt: rbt.print_tree(),
 "plot": lambda rbt: plot_tree(rbt.get_root()),
 "exit": lambda rbt: exit(""),
}
def repl_loop() -> None:
 rbt = RedBlackTree()
 while True:
 try:
 line = input(">> ").rstrip()
 except EOFError:
 exit("")
 tokens = line.split()
 if not tokens:
 continue
 cmd = tokens[0]
 if cmd not in COMMANDS:
 print(f"Error: unknown command: {cmd}.")
 continue
 if cmd in {"print", "exit", "plot"}:
 if len(tokens) != 1:
 print("Error: extra argument.")
 continue
 COMMANDS[cmd](rbt)
 continue
 elif len(tokens) != 2:
 print("Error: expected 2 arguments.")
 continue
 COMMANDS[cmd](rbt, tokens[1])
def main() -> None:
 prompt = (
 "Welcome to RB-Tree REPL.\n"
 "Commands available: insert, delete, search, print, plot, exit.\n"
 )
 print(prompt)
 repl_loop()
if __name__ == "__main__":
 main()

The code has been formatted with black and isort.

Review Request:

Anything. Everything.

asked Apr 9, 2024 at 14:44
\$\endgroup\$

2 Answers 2

4
\$\begingroup\$

It doesn't make sense to pass a string to exit. That's supposed to be an integer returned to the operating system and accessible by a shell as the return code. If you want to indicate success, use 0 instead.

Don't use lambdas if you don't have to -

  • insert and delete can be non-bound references to RedBlackTree.insert and RedBlackTree.delete respectively
  • search should just be a function
  • print should be a non-bound reference to RedBlackTree.print_tree
  • plot should just be a function

Really, you don't need to do length checking at all. Just splat-pass your *tokens to the method, and if it throws, catch and print a message.

You should probably case-fold your command.

Don't hard-code your Commands available list; form that from a join() on your dictionary keys.

answered Apr 10, 2024 at 0:31
\$\endgroup\$
2
  • \$\begingroup\$ exit takes strings, but passing it a string is inappropriate here. If you pass it a string, it's treated as an error message. The exit code is 1 (indicating an error) and the string gets printed before exiting. \$\endgroup\$ Commented Apr 10, 2024 at 1:16
  • 1
    \$\begingroup\$ (Also exit is only supposed to be used in interactive mode, not in programs. Some Python execution settings don't actually have exit. You're supposed to use sys.exit instead.) \$\endgroup\$ Commented Apr 10, 2024 at 1:17
3
\$\begingroup\$

LGTM.

lambdas

Clearly the lambdas work, as-is.

Consider using def instead, in a dedicated module so we can iterate over them. This would open up new possibilities, such as tacking on a number-of-args decorator. Consider adding type annotations.

DRY

COMMANDS = {
 "insert": lambda rbt, x: rbt.insert(x),
 ...
def repl_loop() -> None:
 ...
 if cmd in {"print", "exit", "plot"}:
 if len(tokens) != 1:

This feels a bit redundant and hackish.

Consider putting num_args next to the function definition:

 "insert": (2, lambda rbt, x: rbt.insert(x)),

Consider using try to detect when a "call with wrong number of args" failed, so you can print an informative diagnostic.

Consider using the inspect module to learn how many args a lambda requires.

answered Apr 9, 2024 at 21:07
\$\endgroup\$
2
  • \$\begingroup\$ Re DRY: this should be a namedtuple, probably. \$\endgroup\$ Commented Apr 17, 2024 at 21:53
  • 1
    \$\begingroup\$ @SUTerliakov, Agreed, I am usually quite pleased to see namedtuple incorporated into someone’s design. \$\endgroup\$ Commented Apr 17, 2024 at 22:03

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.