Skip to main content
Code Review

Return to Answer

references != enumeration
Source Link
Daniel
  • 4.6k
  • 2
  • 18
  • 40
  • Most programming languages have a certain style guide associated with them. In the case of Python, it's PEP-8. It is in your best interest to comply with the points outlined there, as doing so will significantly improve readability.

    • Keep vertical whitespace to a minimum. Blank lines can aid in grouping related pieces of code together1, but in my opinion, you've gone a bit overboard. Having just two blank lines in between top-level function definitions is recommended.

    • Your function and variable names follow the PEP-8 naming conventions2. Good job, lots of people get this wrong at first.

    • Whenever you find yourself using an escaped quote character (\' or \"), you can simply surround the string with the other type of quotes.3 This makes the code more readable and reduces the chances of getting syntax errors. To take an example from the piece of code you wrote:

       print('It\'s time to go shopping!')
      

      ... becomes:

       print("It's time to go shopping!")
      
    • It's good practice to separate arguments to functions by a single space.4 An example from shopping_list():

       print('Current cart total: ',sum(item_dict.values()))
      

      ... becomes:

       print('Current cart total: ', sum(item_dict.values()))
      
    • Block comments should start with a space.5

  • It's nice that you added comments, but most of them are plain wrong. Never add comments that are simply a rewording of the code, and always assure your comments are up to date and correct. Let's go over your comments one by one.

    • Lines 3 through 6:

       #create shopping list with automatic calculation
       def display_help():
      

      ... not even close. I guess you reordered your functions at some point and forgot to update this comment.

    • Lines 14 through 17:

       #create a list with the items needed
       #
       def clear_screen():
      

      ... the same goes for this comment. You don't create a list here. You don't do anything here.

    • Lines 22 through 26:

       #Create function to change values of current items or update price of items in the cart
       def shopping_list():
      

      ... finally, a comment that's in the right place. Unfortunately, this one falls under the 'documenting self-documenting code' category.a6 Nitpick: you normally don't create a function, but define it.

    • ...

  • I'm happy you found a way to avoid global variables, but nesting functions is rarely the right solution. show_items() should really be a top-level function, taking one argument.

  • By using f-strings, you're greatly limiting portability. I'd make a safe bet and use str.format() for now.

  • Let's see what happens when I exit the program:

     Welcome! What would you like to do?
     > EXIT
     Goodbye
    

    So far, so good. How about quitting from the 'SHOP' submenu?

     Please enter an item: QUIT
     You have added QUIT to your list
     Price of QUIT:
    

    Whoops, that's not what I was hoping to see. The help message clearly says:

     'QUIT' to exit the program
    

    Peculiar. Now that we're stuck with having to add a new item, let's go through with it and then exit.

     Price of QUIT: 50
     You entered 50.0 as the price of QUIT
     You now have 1 items in your list.
     The total currently on your cart is 50.0
     Would you like to add more items?(Y/N) n
     Here's your cart and your total:
     Traceback (most recent call last):
     File "ttt.py", line 86, in <module>
     begin_attempt()
     File "ttt.py", line 78, in begin_attempt
     shopping_list()
     File "ttt.py", line 64, in shopping_list
     raise KeyboardInterrupt('Goodbye')
     KeyboardInterrupt: Goodbye
    

    Oh my, that's ugly.

    On a more serious note, there should only be one way to exit the program, and it should not be by means of an uncaught exception. You could do this a number of ways:

    • Put all of the prompts in a huge while-loop, then break from the loop when the user wants to exit. This gets messy very quickly. Avoid it.

    • Put all of the prompts in a huge while-loop, then call a function to exit. This is a much better alternative.

    As an aside, it's almost never a good idea to raise a KeyboardInterrupt manually. Even a RuntimeError would be a better fit, but as I explained, cleanly exiting the script is ideal. The sys module provides sys.exit(), which is the best way of quitting Python scripts. Don't use exit(). It is a 'magic'special function and should only be used in the Python REPL.

  • The main menu is broken:

     =======> Help <=======
     'HELP' to display this menu
     'START' to start creating your shopping list
     'SHOW' to display your current items
     'QUIT' to exit the program
     > start
     > show
     > SHOW
     > :(
    
  • try / except-constructs should capture the least amount of code possible. A clear violation of this principle, starting on line 52:

     try:
     ... [12 lines skipped]
     except ValueError:
     print('Please enter a number')
    

    ... the try-block only needs to encompass line 53, because that's the only line that could raise a ValueError.

  • On line 60, the input validation is off. The prompt suggests 'Y' and 'N' are valid inputs, but:

     if add_more_items == 'Y'.lower():
    

    ... indicates it is not. If you want to do case-insensitive comparisons, call str.lower(), like you did in other instances. Alternatively, you could call str.casefold(), which also handles special characters like 'ß':

     >>> "Straße".lower()
     'straße'
     >>> "Straße".casefold()
     'strasse'
    
  • shopping_list is a bad function name. Function names are typically verbs. Maybe play_shopping_game?

  • String concatenation is in many ways inferior to string formatting. It's slower, harder to read, and less versatile: each argument needs to be casted to str if it is not already a string. Always prefer string formatting over concatenation.

NotesReferences

a Don't get me wrong, documenting functions is very important. The 'create a function' part is too verbose nevertheless. If you want to add formal documentation to functions, add docstrings! Docstrings are multiline strings placed below a function or class signature. For example:1 PEP-8: Blank Lines

2 PEP-8: Naming Conventions

3 PEP-8: String Quotes

4 PEP-8: Whitespace in Expressions and Statements

5 PEP-8: Comments: Block Comments

6 Don't get me wrong, documenting functions is very important. The 'create a function' part is too verbose nevertheless. If you want to add formal documentation to functions, add docstrings! Docstrings are multiline strings placed below a function or class signature. For example:

References

  1. PEP-8: Blank Lines

  2. PEP-8: Naming Conventions

  3. PEP-8: String Quotes

  4. PEP-8: Whitespace in Expressions and Statements

  5. PEP-8: Comments: Block Comments

  • Most programming languages have a certain style guide associated with them. In the case of Python, it's PEP-8. It is in your best interest to comply with the points outlined there, as doing so will significantly improve readability.

    • Keep vertical whitespace to a minimum. Blank lines can aid in grouping related pieces of code together1, but in my opinion, you've gone a bit overboard. Having just two blank lines in between top-level function definitions is recommended.

    • Your function and variable names follow the PEP-8 naming conventions2. Good job, lots of people get this wrong at first.

    • Whenever you find yourself using an escaped quote character (\' or \"), you can simply surround the string with the other type of quotes.3 This makes the code more readable and reduces the chances of getting syntax errors. To take an example from the piece of code you wrote:

       print('It\'s time to go shopping!')
      

      ... becomes:

       print("It's time to go shopping!")
      
    • It's good practice to separate arguments to functions by a single space.4 An example from shopping_list():

       print('Current cart total: ',sum(item_dict.values()))
      

      ... becomes:

       print('Current cart total: ', sum(item_dict.values()))
      
    • Block comments should start with a space.5

  • It's nice that you added comments, but most of them are plain wrong. Never add comments that are simply a rewording of the code, and always assure your comments are up to date and correct. Let's go over your comments one by one.

    • Lines 3 through 6:

       #create shopping list with automatic calculation
       def display_help():
      

      ... not even close. I guess you reordered your functions at some point and forgot to update this comment.

    • Lines 14 through 17:

       #create a list with the items needed
       #
       def clear_screen():
      

      ... the same goes for this comment. You don't create a list here. You don't do anything here.

    • Lines 22 through 26:

       #Create function to change values of current items or update price of items in the cart
       def shopping_list():
      

      ... finally, a comment that's in the right place. Unfortunately, this one falls under the 'documenting self-documenting code' category.a Nitpick: you normally don't create a function, but define it.

    • ...

  • I'm happy you found a way to avoid global variables, but nesting functions is rarely the right solution. show_items() should really be a top-level function, taking one argument.

  • By using f-strings, you're greatly limiting portability. I'd make a safe bet and use str.format() for now.

  • Let's see what happens when I exit the program:

     Welcome! What would you like to do?
     > EXIT
     Goodbye
    

    So far, so good. How about quitting from the 'SHOP' submenu?

     Please enter an item: QUIT
     You have added QUIT to your list
     Price of QUIT:
    

    Whoops, that's not what I was hoping to see. The help message clearly says:

     'QUIT' to exit the program
    

    Peculiar. Now that we're stuck with having to add a new item, let's go through with it and then exit.

     Price of QUIT: 50
     You entered 50.0 as the price of QUIT
     You now have 1 items in your list.
     The total currently on your cart is 50.0
     Would you like to add more items?(Y/N) n
     Here's your cart and your total:
     Traceback (most recent call last):
     File "ttt.py", line 86, in <module>
     begin_attempt()
     File "ttt.py", line 78, in begin_attempt
     shopping_list()
     File "ttt.py", line 64, in shopping_list
     raise KeyboardInterrupt('Goodbye')
     KeyboardInterrupt: Goodbye
    

    Oh my, that's ugly.

    On a more serious note, there should only be one way to exit the program, and it should not be by means of an uncaught exception. You could do this a number of ways:

    • Put all of the prompts in a huge while-loop, then break from the loop when the user wants to exit. This gets messy very quickly. Avoid it.

    • Put all of the prompts in a huge while-loop, then call a function to exit. This is a much better alternative.

    As an aside, it's almost never a good idea to raise a KeyboardInterrupt manually. Even a RuntimeError would be a better fit, but as I explained, cleanly exiting the script is ideal. The sys module provides sys.exit(), which is the best way of quitting Python scripts. Don't use exit(). It is a 'magic' function and should only be used in the Python REPL.

  • The main menu is broken:

     =======> Help <=======
     'HELP' to display this menu
     'START' to start creating your shopping list
     'SHOW' to display your current items
     'QUIT' to exit the program
     > start
     > show
     > SHOW
     > :(
    
  • try / except-constructs should capture the least amount of code possible. A clear violation of this principle, starting on line 52:

     try:
     ... [12 lines skipped]
     except ValueError:
     print('Please enter a number')
    

    ... the try-block only needs to encompass line 53, because that's the only line that could raise a ValueError.

  • On line 60, the input validation is off. The prompt suggests 'Y' and 'N' are valid inputs, but:

     if add_more_items == 'Y'.lower():
    

    ... indicates it is not. If you want to do case-insensitive comparisons, call str.lower(), like you did in other instances. Alternatively, you could call str.casefold(), which also handles special characters like 'ß':

     >>> "Straße".lower()
     'straße'
     >>> "Straße".casefold()
     'strasse'
    
  • shopping_list is a bad function name. Function names are typically verbs. Maybe play_shopping_game?

  • String concatenation is in many ways inferior to string formatting. It's slower, harder to read, and less versatile: each argument needs to be casted to str if it is not already a string. Always prefer string formatting over concatenation.

Notes

a Don't get me wrong, documenting functions is very important. The 'create a function' part is too verbose nevertheless. If you want to add formal documentation to functions, add docstrings! Docstrings are multiline strings placed below a function or class signature. For example:

References

  1. PEP-8: Blank Lines

  2. PEP-8: Naming Conventions

  3. PEP-8: String Quotes

  4. PEP-8: Whitespace in Expressions and Statements

  5. PEP-8: Comments: Block Comments

  • Most programming languages have a certain style guide associated with them. In the case of Python, it's PEP-8. It is in your best interest to comply with the points outlined there, as doing so will significantly improve readability.

    • Keep vertical whitespace to a minimum. Blank lines can aid in grouping related pieces of code together1, but in my opinion, you've gone a bit overboard. Having just two blank lines in between top-level function definitions is recommended.

    • Your function and variable names follow the PEP-8 naming conventions2. Good job, lots of people get this wrong at first.

    • Whenever you find yourself using an escaped quote character (\' or \"), you can simply surround the string with the other type of quotes.3 This makes the code more readable and reduces the chances of getting syntax errors. To take an example from the piece of code you wrote:

       print('It\'s time to go shopping!')
      

      ... becomes:

       print("It's time to go shopping!")
      
    • It's good practice to separate arguments to functions by a single space.4 An example from shopping_list():

       print('Current cart total: ',sum(item_dict.values()))
      

      ... becomes:

       print('Current cart total: ', sum(item_dict.values()))
      
    • Block comments should start with a space.5

  • It's nice that you added comments, but most of them are plain wrong. Never add comments that are simply a rewording of the code, and always assure your comments are up to date and correct. Let's go over your comments one by one.

    • Lines 3 through 6:

       #create shopping list with automatic calculation
       def display_help():
      

      ... not even close. I guess you reordered your functions at some point and forgot to update this comment.

    • Lines 14 through 17:

       #create a list with the items needed
       #
       def clear_screen():
      

      ... the same goes for this comment. You don't create a list here. You don't do anything here.

    • Lines 22 through 26:

       #Create function to change values of current items or update price of items in the cart
       def shopping_list():
      

      ... finally, a comment that's in the right place. Unfortunately, this one falls under the 'documenting self-documenting code' category.6 Nitpick: you normally don't create a function, but define it.

    • ...

  • I'm happy you found a way to avoid global variables, but nesting functions is rarely the right solution. show_items() should really be a top-level function, taking one argument.

  • By using f-strings, you're greatly limiting portability. I'd make a safe bet and use str.format() for now.

  • Let's see what happens when I exit the program:

     Welcome! What would you like to do?
     > EXIT
     Goodbye
    

    So far, so good. How about quitting from the 'SHOP' submenu?

     Please enter an item: QUIT
     You have added QUIT to your list
     Price of QUIT:
    

    Whoops, that's not what I was hoping to see. The help message clearly says:

     'QUIT' to exit the program
    

    Peculiar. Now that we're stuck with having to add a new item, let's go through with it and then exit.

     Price of QUIT: 50
     You entered 50.0 as the price of QUIT
     You now have 1 items in your list.
     The total currently on your cart is 50.0
     Would you like to add more items?(Y/N) n
     Here's your cart and your total:
     Traceback (most recent call last):
     File "ttt.py", line 86, in <module>
     begin_attempt()
     File "ttt.py", line 78, in begin_attempt
     shopping_list()
     File "ttt.py", line 64, in shopping_list
     raise KeyboardInterrupt('Goodbye')
     KeyboardInterrupt: Goodbye
    

    Oh my, that's ugly.

    On a more serious note, there should only be one way to exit the program, and it should not be by means of an uncaught exception. You could do this a number of ways:

    • Put all of the prompts in a huge while-loop, then break from the loop when the user wants to exit. This gets messy very quickly. Avoid it.

    • Put all of the prompts in a huge while-loop, then call a function to exit. This is a much better alternative.

    As an aside, it's almost never a good idea to raise a KeyboardInterrupt manually. Even a RuntimeError would be a better fit, but as I explained, cleanly exiting the script is ideal. The sys module provides sys.exit(), which is the best way of quitting Python scripts. Don't use exit(). It is a special function and should only be used in the Python REPL.

  • The main menu is broken:

     =======> Help <=======
     'HELP' to display this menu
     'START' to start creating your shopping list
     'SHOW' to display your current items
     'QUIT' to exit the program
     > start
     > show
     > SHOW
     > :(
    
  • try / except-constructs should capture the least amount of code possible. A clear violation of this principle, starting on line 52:

     try:
     ... [12 lines skipped]
     except ValueError:
     print('Please enter a number')
    

    ... the try-block only needs to encompass line 53, because that's the only line that could raise a ValueError.

  • On line 60, the input validation is off. The prompt suggests 'Y' and 'N' are valid inputs, but:

     if add_more_items == 'Y'.lower():
    

    ... indicates it is not. If you want to do case-insensitive comparisons, call str.lower(), like you did in other instances. Alternatively, you could call str.casefold(), which also handles special characters like 'ß':

     >>> "Straße".lower()
     'straße'
     >>> "Straße".casefold()
     'strasse'
    
  • shopping_list is a bad function name. Function names are typically verbs. Maybe play_shopping_game?

  • String concatenation is in many ways inferior to string formatting. It's slower, harder to read, and less versatile: each argument needs to be casted to str if it is not already a string. Always prefer string formatting over concatenation.

References

1 PEP-8: Blank Lines

2 PEP-8: Naming Conventions

3 PEP-8: String Quotes

4 PEP-8: Whitespace in Expressions and Statements

5 PEP-8: Comments: Block Comments

6 Don't get me wrong, documenting functions is very important. The 'create a function' part is too verbose nevertheless. If you want to add formal documentation to functions, add docstrings! Docstrings are multiline strings placed below a function or class signature. For example:

added 83 characters in body
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238
  • Most programming languages have a certain style guide associated with them. In the case of Python, it's PEP-8. It is in your best interest to comply with the points outlined there, as doing so will significantly improve readability.

    • Keep vertical whitespace to a minimum. Blank lines can aid in grouping related pieces of code together1, but in my opinion, you've gone a bit overboard. Having just two blank lines in between top-level function definitions is recommended.

    • Your function and variable names follow the PEP-8 naming conventions2. Good job, lots of people get this wrong at first.

    • Whenever you find yourself using an escaped quote character (\' or \"), you can simply surround the string with the other type of quotes.3 This makes the code more readable and reduces the chances of getting syntax errors. To take an example from the piece of code you wrote:

       print('It\'s time to go shopping!')
      

      ... becomes:

       print("It's time to go shopping!")
      
    • It's good practice to separate arguments to functions by a single space.4 An example from shopping_list():

       print('Current cart total: ',sum(item_dict.values()))
      

      ... becomes:

       print('Current cart total: ', sum(item_dict.values()))
      
    • Block comments should start with a space.5

  • It's nice that you added comments, but most of them are plain wrong. Never add comments that are simply a rewording of the code, and always assure your comments are up to date and correct. Let's go over your comments one by one.

    • Lines 3 through 6:

       #create shopping list with automatic calculation
       def display_help():
      

      ... not even close. I guess you reordered your functions at some point and forgot to update this comment.

    • Lines 14 through 17:

       #create a list with the items needed
       #
       def clear_screen():
      

      ... the same goes for this comment. You don't create a list here. You don't do anything here.

    • Lines 22 through 26:

       #Create function to change values of current items or update price of items in the cart
       def shopping_list():
      

      ... finally, a comment that's in the right place. Unfortunately, this one falls under the 'documenting self-documenting code' category.a Nitpick: you normally don't create a function, but define it.

    • ...

  • I'm happy you found a way to avoid global variables, but nesting functions is rarely the right solution. show_items() should really be a top-level function, taking one argument.

  • By using f-strings, you're greatly limiting portability. I'd make a safe bet and use str.format() for now.

  • Let's see what happens when I exit the program:

     Welcome! What would you like to do?
     > EXIT
     Goodbye
    
     Welcome! What would you like to do?
     > EXIT
     Goodbye
    

    So far, so good. How about quitting from the 'SHOP' submenu?

     Please enter an item: QUIT
     You have added QUIT to your list
     Price of QUIT:
    
     Please enter an item: QUIT
     You have added QUIT to your list
     Price of QUIT:
    

    Whoops, that's not what I was hoping to see. The help message clearly says:

     'QUIT' to exit the program
    
     'QUIT' to exit the program
    

    Peculiar. Now that we're stuck with having to add a new item, let's go through with it and then exit.

     Price of QUIT: 50
     You entered 50.0 as the price of QUIT
     You now have 1 items in your list.
     The total currently on your cart is 50.0
     Would you like to add more items?(Y/N) n
     Here's your cart and your total:
     Traceback (most recent call last):
     File "ttt.py", line 86, in <module>
     begin_attempt()
     File "ttt.py", line 78, in begin_attempt
     shopping_list()
     File "ttt.py", line 64, in shopping_list
     raise KeyboardInterrupt('Goodbye')
     KeyboardInterrupt: Goodbye
    
     Price of QUIT: 50
     You entered 50.0 as the price of QUIT
     You now have 1 items in your list.
     The total currently on your cart is 50.0
     Would you like to add more items?(Y/N) n
     Here's your cart and your total:
     Traceback (most recent call last):
     File "ttt.py", line 86, in <module>
     begin_attempt()
     File "ttt.py", line 78, in begin_attempt
     shopping_list()
     File "ttt.py", line 64, in shopping_list
     raise KeyboardInterrupt('Goodbye')
     KeyboardInterrupt: Goodbye
    

    Oh my, that's ugly.

    On a more serious note, there should only be one way to exit the program, and it should not be by means of an uncaught exception. You could do this a number of ways:

    • Put all of the prompts in a huge while-loop, then break from the loop when the user wants to exit. This gets messy very quickly. Avoid it.

    • Put all of the prompts in a huge while-loop, then call a function to exit. This is a much better alternative.

    As an aside, it's almost never a good idea to raise a KeyboardInterrupt manually. Even a RuntimeError would be a better fit, but as I explained, cleanly exiting the script is ideal. The sys module provides sys.exit(), which is the best way of quitting Python scripts. Don't use exit(). It is a 'magic' function and should only be used in the Python REPL.

  • The main menu is broken:

     =======> Help <=======
     'HELP' to display this menu
     'START' to start creating your shopping list
     'SHOW' to display your current items
     'QUIT' to exit the program
     > start
     > show
     > SHOW
     > :(
    
     =======> Help <=======
     'HELP' to display this menu
     'START' to start creating your shopping list
     'SHOW' to display your current items
     'QUIT' to exit the program
     > start
     > show
     > SHOW
     > :(
    
  • try / except-constructs should capture the least amount of code possible. A clear violation of this principle, starting on line 52:

     try:
     ... [12 lines skipped]
     except ValueError:
     print('Please enter a number')
    
     try:
     ... [12 lines skipped]
     except ValueError:
     print('Please enter a number')
    

    ... the try-block only needs to encompass line 53, because that's the only line that could raise a ValueError.

  • On line 60, the input validation is off. The prompt suggests 'Y' and 'N' are valid inputs, but:

     if add_more_items == 'Y'.lower():
    
     if add_more_items == 'Y'.lower():
    

    ... indicates it is not. If you want to do case-insensitive comparisons, call str.lower(), like you did in other instances. Alternatively, you could call str.casefold(), which also handles special characters like 'ß':

     >>> "Straße".lower()
     'straße'
     >>> "Straße".casefold()
     'strasse'
    
     >>> "Straße".lower()
     'straße'
     >>> "Straße".casefold()
     'strasse'
    
  • shopping_list is a bad function name. Function names are typically verbs. Maybe play_shopping_game?

  • String concatenation is in many ways inferior to string formatting. It's slower, harder to read, and less versatile: each argument needs to be casted to str if it is not already a string. Always prefer string formatting over concatenation.

def add(a, b):
 """Return `a` + `b`. Both arguments must be numbers."""
 return a + b
def add(a, b):
 """Return `a` + `b`. Both arguments must be numbers."""
 return a + b
>>> add.__doc__
'Return `a` + `b`. Both arguments must be numbers.'
>>> add.__doc__
'Return `a` + `b`. Both arguments must be numbers.'
add(a, b)
 Return `a` + `b`. Both arguments must be numbers.
add(a, b)
 Return `a` + `b`. Both arguments must be numbers.

1 PEP-8: Blank Lines

2 PEP-8: Naming Conventions

3 PEP-8: String Quotes

4 PEP-8: Whitespace in Expressions and Statements

5 PEP-8: Comments: Block Comments

  1. PEP-8: Blank Lines

  2. PEP-8: Naming Conventions

  3. PEP-8: String Quotes

  4. PEP-8: Whitespace in Expressions and Statements

  5. PEP-8: Comments: Block Comments

  • Most programming languages have a certain style guide associated with them. In the case of Python, it's PEP-8. It is in your best interest to comply with the points outlined there, as doing so will significantly improve readability.

    • Keep vertical whitespace to a minimum. Blank lines can aid in grouping related pieces of code together1, but in my opinion, you've gone a bit overboard. Having just two blank lines in between top-level function definitions is recommended.

    • Your function and variable names follow the PEP-8 naming conventions2. Good job, lots of people get this wrong at first.

    • Whenever you find yourself using an escaped quote character (\' or \"), you can simply surround the string with the other type of quotes.3 This makes the code more readable and reduces the chances of getting syntax errors. To take an example from the piece of code you wrote:

       print('It\'s time to go shopping!')
      

      ... becomes:

       print("It's time to go shopping!")
      
    • It's good practice to separate arguments to functions by a single space.4 An example from shopping_list():

       print('Current cart total: ',sum(item_dict.values()))
      

      ... becomes:

       print('Current cart total: ', sum(item_dict.values()))
      
    • Block comments should start with a space.5

  • It's nice that you added comments, but most of them are plain wrong. Never add comments that are simply a rewording of the code, and always assure your comments are up to date and correct. Let's go over your comments one by one.

    • Lines 3 through 6:

       #create shopping list with automatic calculation
       def display_help():
      

      ... not even close. I guess you reordered your functions at some point and forgot to update this comment.

    • Lines 14 through 17:

       #create a list with the items needed
       #
       def clear_screen():
      

      ... the same goes for this comment. You don't create a list here. You don't do anything here.

    • Lines 22 through 26:

       #Create function to change values of current items or update price of items in the cart
       def shopping_list():
      

      ... finally, a comment that's in the right place. Unfortunately, this one falls under the 'documenting self-documenting code' category.a Nitpick: you normally don't create a function, but define it.

    • ...

  • I'm happy you found a way to avoid global variables, but nesting functions is rarely the right solution. show_items() should really be a top-level function, taking one argument.

  • By using f-strings, you're greatly limiting portability. I'd make a safe bet and use str.format() for now.

  • Let's see what happens when I exit the program:

     Welcome! What would you like to do?
     > EXIT
     Goodbye
    

    So far, so good. How about quitting from the 'SHOP' submenu?

     Please enter an item: QUIT
     You have added QUIT to your list
     Price of QUIT:
    

    Whoops, that's not what I was hoping to see. The help message clearly says:

     'QUIT' to exit the program
    

    Peculiar. Now that we're stuck with having to add a new item, let's go through with it and then exit.

     Price of QUIT: 50
     You entered 50.0 as the price of QUIT
     You now have 1 items in your list.
     The total currently on your cart is 50.0
     Would you like to add more items?(Y/N) n
     Here's your cart and your total:
     Traceback (most recent call last):
     File "ttt.py", line 86, in <module>
     begin_attempt()
     File "ttt.py", line 78, in begin_attempt
     shopping_list()
     File "ttt.py", line 64, in shopping_list
     raise KeyboardInterrupt('Goodbye')
     KeyboardInterrupt: Goodbye
    

    Oh my, that's ugly.

    On a more serious note, there should only be one way to exit the program, and it should not be by means of an uncaught exception. You could do this a number of ways:

    • Put all of the prompts in a huge while-loop, then break from the loop when the user wants to exit. This gets messy very quickly. Avoid it.

    • Put all of the prompts in a huge while-loop, then call a function to exit. This is a much better alternative.

    As an aside, it's almost never a good idea to raise a KeyboardInterrupt manually. Even a RuntimeError would be a better fit, but as I explained, cleanly exiting the script is ideal. The sys module provides sys.exit(), which is the best way of quitting Python scripts. Don't use exit(). It is a 'magic' function and should only be used in the Python REPL.

  • The main menu is broken:

     =======> Help <=======
     'HELP' to display this menu
     'START' to start creating your shopping list
     'SHOW' to display your current items
     'QUIT' to exit the program
     > start
     > show
     > SHOW
     > :(
    
  • try / except-constructs should capture the least amount of code possible. A clear violation of this principle, starting on line 52:

     try:
     ... [12 lines skipped]
     except ValueError:
     print('Please enter a number')
    

    ... the try-block only needs to encompass line 53, because that's the only line that could raise a ValueError.

  • On line 60, the input validation is off. The prompt suggests 'Y' and 'N' are valid inputs, but:

     if add_more_items == 'Y'.lower():
    

    ... indicates it is not. If you want to do case-insensitive comparisons, call str.lower(), like you did in other instances. Alternatively, you could call str.casefold(), which also handles special characters like 'ß':

     >>> "Straße".lower()
     'straße'
     >>> "Straße".casefold()
     'strasse'
    
  • shopping_list is a bad function name. Function names are typically verbs. Maybe play_shopping_game?

  • String concatenation is in many ways inferior to string formatting. It's slower, harder to read, and less versatile: each argument needs to be casted to str if it is not already a string. Always prefer string formatting over concatenation.

def add(a, b):
 """Return `a` + `b`. Both arguments must be numbers."""
 return a + b
>>> add.__doc__
'Return `a` + `b`. Both arguments must be numbers.'
add(a, b)
 Return `a` + `b`. Both arguments must be numbers.

1 PEP-8: Blank Lines

2 PEP-8: Naming Conventions

3 PEP-8: String Quotes

4 PEP-8: Whitespace in Expressions and Statements

5 PEP-8: Comments: Block Comments

  • Most programming languages have a certain style guide associated with them. In the case of Python, it's PEP-8. It is in your best interest to comply with the points outlined there, as doing so will significantly improve readability.

    • Keep vertical whitespace to a minimum. Blank lines can aid in grouping related pieces of code together1, but in my opinion, you've gone a bit overboard. Having just two blank lines in between top-level function definitions is recommended.

    • Your function and variable names follow the PEP-8 naming conventions2. Good job, lots of people get this wrong at first.

    • Whenever you find yourself using an escaped quote character (\' or \"), you can simply surround the string with the other type of quotes.3 This makes the code more readable and reduces the chances of getting syntax errors. To take an example from the piece of code you wrote:

       print('It\'s time to go shopping!')
      

      ... becomes:

       print("It's time to go shopping!")
      
    • It's good practice to separate arguments to functions by a single space.4 An example from shopping_list():

       print('Current cart total: ',sum(item_dict.values()))
      

      ... becomes:

       print('Current cart total: ', sum(item_dict.values()))
      
    • Block comments should start with a space.5

  • It's nice that you added comments, but most of them are plain wrong. Never add comments that are simply a rewording of the code, and always assure your comments are up to date and correct. Let's go over your comments one by one.

    • Lines 3 through 6:

       #create shopping list with automatic calculation
       def display_help():
      

      ... not even close. I guess you reordered your functions at some point and forgot to update this comment.

    • Lines 14 through 17:

       #create a list with the items needed
       #
       def clear_screen():
      

      ... the same goes for this comment. You don't create a list here. You don't do anything here.

    • Lines 22 through 26:

       #Create function to change values of current items or update price of items in the cart
       def shopping_list():
      

      ... finally, a comment that's in the right place. Unfortunately, this one falls under the 'documenting self-documenting code' category.a Nitpick: you normally don't create a function, but define it.

    • ...

  • I'm happy you found a way to avoid global variables, but nesting functions is rarely the right solution. show_items() should really be a top-level function, taking one argument.

  • By using f-strings, you're greatly limiting portability. I'd make a safe bet and use str.format() for now.

  • Let's see what happens when I exit the program:

     Welcome! What would you like to do?
     > EXIT
     Goodbye
    

    So far, so good. How about quitting from the 'SHOP' submenu?

     Please enter an item: QUIT
     You have added QUIT to your list
     Price of QUIT:
    

    Whoops, that's not what I was hoping to see. The help message clearly says:

     'QUIT' to exit the program
    

    Peculiar. Now that we're stuck with having to add a new item, let's go through with it and then exit.

     Price of QUIT: 50
     You entered 50.0 as the price of QUIT
     You now have 1 items in your list.
     The total currently on your cart is 50.0
     Would you like to add more items?(Y/N) n
     Here's your cart and your total:
     Traceback (most recent call last):
     File "ttt.py", line 86, in <module>
     begin_attempt()
     File "ttt.py", line 78, in begin_attempt
     shopping_list()
     File "ttt.py", line 64, in shopping_list
     raise KeyboardInterrupt('Goodbye')
     KeyboardInterrupt: Goodbye
    

    Oh my, that's ugly.

    On a more serious note, there should only be one way to exit the program, and it should not be by means of an uncaught exception. You could do this a number of ways:

    • Put all of the prompts in a huge while-loop, then break from the loop when the user wants to exit. This gets messy very quickly. Avoid it.

    • Put all of the prompts in a huge while-loop, then call a function to exit. This is a much better alternative.

    As an aside, it's almost never a good idea to raise a KeyboardInterrupt manually. Even a RuntimeError would be a better fit, but as I explained, cleanly exiting the script is ideal. The sys module provides sys.exit(), which is the best way of quitting Python scripts. Don't use exit(). It is a 'magic' function and should only be used in the Python REPL.

  • The main menu is broken:

     =======> Help <=======
     'HELP' to display this menu
     'START' to start creating your shopping list
     'SHOW' to display your current items
     'QUIT' to exit the program
     > start
     > show
     > SHOW
     > :(
    
  • try / except-constructs should capture the least amount of code possible. A clear violation of this principle, starting on line 52:

     try:
     ... [12 lines skipped]
     except ValueError:
     print('Please enter a number')
    

    ... the try-block only needs to encompass line 53, because that's the only line that could raise a ValueError.

  • On line 60, the input validation is off. The prompt suggests 'Y' and 'N' are valid inputs, but:

     if add_more_items == 'Y'.lower():
    

    ... indicates it is not. If you want to do case-insensitive comparisons, call str.lower(), like you did in other instances. Alternatively, you could call str.casefold(), which also handles special characters like 'ß':

     >>> "Straße".lower()
     'straße'
     >>> "Straße".casefold()
     'strasse'
    
  • shopping_list is a bad function name. Function names are typically verbs. Maybe play_shopping_game?

  • String concatenation is in many ways inferior to string formatting. It's slower, harder to read, and less versatile: each argument needs to be casted to str if it is not already a string. Always prefer string formatting over concatenation.

def add(a, b):
 """Return `a` + `b`. Both arguments must be numbers."""
 return a + b
>>> add.__doc__
'Return `a` + `b`. Both arguments must be numbers.'
add(a, b)
 Return `a` + `b`. Both arguments must be numbers.
  1. PEP-8: Blank Lines

  2. PEP-8: Naming Conventions

  3. PEP-8: String Quotes

  4. PEP-8: Whitespace in Expressions and Statements

  5. PEP-8: Comments: Block Comments

added 179 characters in body
Source Link
Daniel
  • 4.6k
  • 2
  • 18
  • 40

In the Python REPL, youYou can access the docstring as the object's __doc__ attribute:

>>> add.__doc__
'Return `a` + `b`. Both arguments must be numbers.'

... and in the Python REPL, you can use the built-in help() :

add(a, b)
 Return `a` + `b`. Both arguments must be numbers.

In the Python REPL, you can access the docstring as the object's __doc__ attribute:

>>> add.__doc__
'Return `a` + `b`. Both arguments must be numbers.'

You can access the docstring as the object's __doc__ attribute:

>>> add.__doc__
'Return `a` + `b`. Both arguments must be numbers.'

... and in the Python REPL, you can use the built-in help() :

add(a, b)
 Return `a` + `b`. Both arguments must be numbers.
added 2 characters in body
Source Link
Daniel
  • 4.6k
  • 2
  • 18
  • 40
Loading
added 156 characters in body
Source Link
Daniel
  • 4.6k
  • 2
  • 18
  • 40
Loading
added 156 characters in body
Source Link
Daniel
  • 4.6k
  • 2
  • 18
  • 40
Loading
added 156 characters in body
Source Link
Daniel
  • 4.6k
  • 2
  • 18
  • 40
Loading
added 156 characters in body
Source Link
Daniel
  • 4.6k
  • 2
  • 18
  • 40
Loading
Source Link
Daniel
  • 4.6k
  • 2
  • 18
  • 40
Loading
lang-py

AltStyle によって変換されたページ (->オリジナル) /