- **Docstrings**: You should include a [`docstring`][1] at the beginning of every method/class/module you write. This will help any documentation identify what your code is supposed to do. - **Naming**: Python variables and parameters should be in `snake_case`, not `camelCase`. - **`len` as condition**: You shouldn't use `if len(self.title):`, instead you should check if it doesn't exist, `if not self.title`, as it is more compliant with PEP-8. [This StackOverflow answer][2] provides more insight. - **String formatting**: This one is a personal preference. I like to use `f""` to format my strings because it allows me to directly include variables into the string, without having to chain a `.format()` onto the end. Again, this is purely personal, but see how you like it. - **Imports**: Another personal preference, I like to organize my imports alphabetically so it's more organized. This is all up to you if you want to keep with this practice, but do make sure to follow [PEP-8 Import Guide][3] to make sure you're following standard and accepted practies. - **Unnecessary methods**: `show_title` and `show_header` is basically extra and unneeded code. You're essentially redefining the `print` method. Just print the title/header whenever you need to, instead of calling these methods. ***Updated Code*** import os import sys class Menu(): """ Menu class for displaying and adding to menu """ def __init__(self, *items, **kwargs): self.items = [] self.title = kwargs.get('title', '') self.header = kwargs.get('header', '') for item in items: self.add(item) def add(self, *items): """ Adds each element in `list` to items """ for item in items: self.items.append(item) if hasattr(item, 'sub_menu'): self.add_parent_to_child(item.sub_menu) def show(self): """ Displays the items and calls method to collect user input """ clear() if self.header: print(self.header) if self.title: print(self.title) for i, item in enumerate(self.items): print(f"[{i + 1}] {item.title}") self.choice() def choice(self): """ Collects user input """ while 1: try: choice = input('> ') if choice == 'q': clear() sys.exit() if choice == 'b': if hasattr(self, 'parent'): self.show() else: self.show() continue if not choice.isdigit(): raise ValueError item = self.items[int(choice) - 1] if hasattr(item, 'callback'): item.callback() if hasattr(item, 'sub_menu'): item.sub_menu.show() if not hasattr(item, 'sub_menu') and not hasattr(item, 'callback'): print(f"{item.title} is an empty menu...") except (ValueError, IndexError): self.show() continue def add_parent_to_child(self, child): """ Adds the passed `child` to the parent of the object """ child.parent = self class MenuItem(object): """ Specific class for items in the menu """ def __init__(self, title, sub_menu=None, callback=None, tag=''): self.title = title if sub_menu is not None: self.sub_menu = sub_menu if self.title: sub_menu.title = self.title if callback is not None: self.callback = callback if tag: self.tag = tag def clear(): """ Clears the console screen """ os.system('cls') if os.name == 'nt' else os.system('clear') if __name__ == '__main__': ITEM_1 = MenuItem('empty test 1') ITEM_2 = MenuItem('empty test 2') SUBMENU_1 = Menu(ITEM_1, ITEM_2) ITEM_3 = MenuItem('sub menu', sub_menu=SUBMENU_1) TEST_MENU = Menu(ITEM_1, ITEM_2, ITEM_3, title='Main Menu') TEST_MENU.show() [1]: https://www.python.org/dev/peps/pep-0008/#documentation-strings [2]: https://stackoverflow.com/a/43476778/8968906 [3]: https://www.python.org/dev/peps/pep-0008/#imports