python console menu level looping

ROGER GRAYDON CHRISTMAN dvl at psu.edu
Mon Sep 25 11:51:20 EDT 2017



On Mon, Sep 24, 2017 09:41 PM, Daiyue Weng <daiyueweng at gmail.com> wrote:
>
Hi, I tried to make a menu using print statements in Python 3. The code is
>as follows,
>
>print('insert data into: ')
>data_insert_method = ['new collection', 'existing collection']
>for index, elem in enumerate(data_insert_method):
>print(index, '-', elem)
>
>while 1:
>how_to_insert = input('Choose a method for inserting data: ')
>if how_to_insert:
>try:
>how_to_insert = int(how_to_insert)
>how_to_insert = data_insert_method[how_to_insert]
>break
>except ValueError:
>print('Please type in an integer corresponding to the data insert method')
>continue
>except IndexError:
>print('insert method index out of range')
>continue
>
>if how_to_insert == 'new collection':
>
>print('Set up collection name : ')
>db_name_setup = ['manual setup', 'return to the main menu']
>for index, elem in enumerate(db_name_setup):
>print(index, '-', elem)
>
>while 1:
>how_to_setup = input('Choose a method for setting up collection: ')
>if how_to_setup:
>try:
>how_to_setup = int(how_to_setup)
>how_to_setup = db_name_setup[how_to_setup]
>break
>except ValueError:
>print('Please type in an integer corresponding to the collection setup
>method')
>continue
>except IndexError:
>print('collection setup method index out of range')
>continue
>
>if how_to_setup == 'manual setup':
>print('Please type in collection name: ')
>elif how_to_setup == 'return to main menu':
>print('return to main menu')
>
>It is a 2-level menu, on the 2nd level menu 'new collection', there is an
>option - 'return to the main menu', I am wondering how to loop back to the
>1st level menu, i.e. ['new collection', 'existing collection'],
>whenever 'return
>to the main menu' is selected.
>



As one of those pesky teacher purists, my first response is 'ick'.

I see 'break' statements used for 'normal' loop exits.

I see 'continue' statements that have no effect, so serve no purpose.

I see lists being used just for display purposes, and not to actually solve any
problem

and then the question about 'how to loop back' at the end

-- if you want to go from the bottom of a loop to the top of loop,

all you have to do is make sure they are the same loop


I would take this approach:


I am inserting .'s to indent, because I do not trust my mailer

to preserve the indentation


data_insert_method = ['exit program',new collection','existing collection']   

db_name_setup = ['return to previous menu','manual setup']


first_menu = -1    # feed the first loop

while first_menu != 0::

. . for counterin range(len(data_insert_method)):

. . . . index = (counter+1) % len(data_insert_method)

. . . . print(index,'-',data_insert_method(index)

. . . . # the quit option is always 0, and appears last

. . . . # obtain and verify integer input here

. . . . if first_menu == 1:        # new collection

. . . . . . second_menu = -1

. . . . . . while second_menu != 0:

. . . . . . . . # the same thing as the outer loop, just nested

. . . . . . . < trim >

. . . . elif first_menu == 2:    # existing collection



There are still some wide open design problems here:

It seems the only difference between 'new collection' and

'existing collection' is whether data already exists.

But the code structure as presented seems to suggest that

there will be one whole section to the program that works

on an empty set, and different whole section that works on

a non-emtpty set -- which suggests a humongous amount

of unnecessary code duplication.


Do you really expect to go back to the outer menu for

'new collection' more than once, when running this program,

or does it seem more likely that initalizing an empty data base

would happen only once at program startup, after which it

behaves just like an 'existing collection' with less data?



As someone else pointed out, your tests along the lines of

if how_to_insert == 'new collection':

are error prone, just from typing errors.    If you are going to

have a user type in discrete integers, you might as well

just test using those integers.


On the other hand, if you intend to make the code's decisions

appear to be self-documenting, then skip the integers completely,

and instead use string inputs, like single letters or short keywords.

That would then eliminate any worry about ValueErrors.

A dictionary can easily associate the short inputs with the

longer method descriptions, and could even conceivably

link directly to a function object.


Roger Christman

Pennsylvania State University


 




More information about the Python-list mailing list