filter input("search for"notes self notebook search(filterself show_notes(notesdef add_note(self)memo input("enter memo"self notebook new_note(memoprint("your note has been added "def modify_note(self)id input("enter note id"memo input("enter memo"tags input("enter tags"if memoself notebook modify_memo(idmemoif tagsself notebook modify_tags(idtagsdef quit(self)print("thank you for using your notebook today "sys exit( if __name__ ="__main__"menu(run(this code first imports the notebook objects using an absolute import relative imports wouldn' work because we haven' placed our code inside package the menu class' run method repeatedly displays menu and responds to choices by calling functions on the notebook this is done using an idiom that is rather peculiar to pythonit is lightweight version of the command pattern that we will discuss in python design patterns the choices entered by the user are strings in the menu' __init__ methodwe create dictionary that maps strings to functions on the menu object itself thenwhen the user makes choicewe retrieve the object from the dictionary the action variable actually refers to specific methodand is called by appending empty brackets (since none of the methods require parametersto the variable of coursethe user might have entered an inappropriate choiceso we check if the action really exists before calling it each of the various methods request user input and call appropriate methods on the notebook object associated with it for the search implementationwe notice that after we've filtered the noteswe need to show them to the userso we make the show_notes function serve double dutyit accepts an optional notes parameter if it' suppliedit displays only the filtered notesbut if it' notit displays all notes since the notes parameter is optionalshow_notes can still be called with no parameters as an empty menu item