Skip to main content
replaced http://codereview.stackexchange.com/ with https://codereview.stackexchange.com/
Source Link
  • Using __doc__ to get the docstring for display_help – In Python you can and should describe your code using docstrings, typically text with triple quotes, i.e. """ ... """. These can be used to describe the module, functions, classes (and methods). They typically come on the line after the definition of the item you want to document.

    A neat thing is that this docstring can be accessed using a special variable, __doc__, or for a function as display_help.__doc__. And then it can be used for print outs, or similar.

  • Work a little more on naming methods – It is not very common in Python to have get_xxxx methods, rather name them according to specific function, like roll_multiple_dice() or roll_die(). Aim for simplicity and clarity. Using get_answer() implies that you want me to insert the answer of something, whilst number_of_pythons() indicates that this is going to be calculated.

  • List comprehensions are your friend – Instead of repeating code to build the list, use return [roll_die() for _ in range(number_of_dice)] which implements three nice features:

    1. A list comprehension, which builds a list based on the inner generator, i.e. [ ... ]
    2. The use of for within the generator, x for x in range(y), which compresses a for loop into the expression. This one would return the numbers from 0 to y-1
    3. The use of _ when we don't really care about the number, but just want the code in front of the for loop to be executed
  • Generator expressions – The for loop of last item, can also be used outside of list comprehension, i.e sum(x for x in range(y)), which would sum all the numbers from 0 through y-1.

    One major difference between a list comprehension and generator, is that the list comprehension actually builds the entire list, whilst the generators works in the background and gives you another element when you want it.

    In the sum example this means that if you had y=1000000 you wouldn't allocate memory for more than 1 int, whilst if you used list comprehension you would allocate the entire list of 1 million elements, and then sum it.

  • The Python ternary, i.e. a = b if c else d – This could take some time to get used to, but actually it reads out quite nicely: Set the value of a to b if the condition c is true, or d if not true.

    Disclaimer: In my refactored code this is where it got a little ugly, as I combined multiple of this construction. But still, they kind of make sense. I used them in both number_of_pythons() and print_dice().

  • Avoid one-time intermediate variable – It's quite common to skip the intermediate variable, especially if you use them only once, and rather use the expression directly. I.e. in roll_die() just return the random number, and in roll_multiple_dice() return the list directly.

  • In some cases, you can sum using Booleans – Doing the if True: a += 1 is kind of an anti-pattern, and can in some cases be replaced by a += True, or in your case: streak += play_once(...).

    • Bug found by 200_success: Here the simplification went too far, as I by simply summing, removed the resetting of the streak counter.
  • Avoid flag variables, if possible – Your use of valid in get_guess() is better written using while True and a break like in your input validations. And skipping the intermediate variable, you could return straight out of the loop.

  • Try to avoid the chained if commands, doing the same stuff – In both get_answer() and print_dice() you have if chains where the block kind of does the same. This is usually an indication that you could find a better way of handling it.

    • In get_answer() I opted for a double ternary, doing answer += 2 if i == 3 else 4 if i == 5 else 0.

    • In print_dice() I used the fact that a six sided die has only 5 distinct patterns, and then I used yet another double ternary to select from the different options.

      _Disclaimer:_ Even though this code is a lot shorter than yours, that doesn't mean it is nicer as such. But it does show an alternate way, and there are multiple ways to print die results. See [here](httphttps://codereview.stackexchange.com/q/111337/78136) or [here](https://codegolf.stackexchange.com/a/2603/45969).
      
  • Use constants, not magic number – Instead of hiding a 5 and an 8 in the code, use constants at top of file like REQUIRED_STREAK_RUN = 8 and NUMBER_OF_DICE = 5. This allows you to change them easily (and you can still make the document reflect the change using str.format()

  • Use str.format() for string formatting - This is a very useful construct, which is well worth some time to look into. You could either use it without names (see end of play_once()), or you could name your variables like in display_help().

    PS! If using Python 2, I recommend using from __future__ import print_function to get the full extent of this beauty there as well.

  • Feature: You can't quit your program without becoming a Pythentate – I think it's nice to give users a way out. I've implemented a lazy version with terminating if entering a negative answer. This could be done a lot nicer, but it should be an option to quit at any time.

  • Using __doc__ to get the docstring for display_help – In Python you can and should describe your code using docstrings, typically text with triple quotes, i.e. """ ... """. These can be used to describe the module, functions, classes (and methods). They typically come on the line after the definition of the item you want to document.

    A neat thing is that this docstring can be accessed using a special variable, __doc__, or for a function as display_help.__doc__. And then it can be used for print outs, or similar.

  • Work a little more on naming methods – It is not very common in Python to have get_xxxx methods, rather name them according to specific function, like roll_multiple_dice() or roll_die(). Aim for simplicity and clarity. Using get_answer() implies that you want me to insert the answer of something, whilst number_of_pythons() indicates that this is going to be calculated.

  • List comprehensions are your friend – Instead of repeating code to build the list, use return [roll_die() for _ in range(number_of_dice)] which implements three nice features:

    1. A list comprehension, which builds a list based on the inner generator, i.e. [ ... ]
    2. The use of for within the generator, x for x in range(y), which compresses a for loop into the expression. This one would return the numbers from 0 to y-1
    3. The use of _ when we don't really care about the number, but just want the code in front of the for loop to be executed
  • Generator expressions – The for loop of last item, can also be used outside of list comprehension, i.e sum(x for x in range(y)), which would sum all the numbers from 0 through y-1.

    One major difference between a list comprehension and generator, is that the list comprehension actually builds the entire list, whilst the generators works in the background and gives you another element when you want it.

    In the sum example this means that if you had y=1000000 you wouldn't allocate memory for more than 1 int, whilst if you used list comprehension you would allocate the entire list of 1 million elements, and then sum it.

  • The Python ternary, i.e. a = b if c else d – This could take some time to get used to, but actually it reads out quite nicely: Set the value of a to b if the condition c is true, or d if not true.

    Disclaimer: In my refactored code this is where it got a little ugly, as I combined multiple of this construction. But still, they kind of make sense. I used them in both number_of_pythons() and print_dice().

  • Avoid one-time intermediate variable – It's quite common to skip the intermediate variable, especially if you use them only once, and rather use the expression directly. I.e. in roll_die() just return the random number, and in roll_multiple_dice() return the list directly.

  • In some cases, you can sum using Booleans – Doing the if True: a += 1 is kind of an anti-pattern, and can in some cases be replaced by a += True, or in your case: streak += play_once(...).

    • Bug found by 200_success: Here the simplification went too far, as I by simply summing, removed the resetting of the streak counter.
  • Avoid flag variables, if possible – Your use of valid in get_guess() is better written using while True and a break like in your input validations. And skipping the intermediate variable, you could return straight out of the loop.

  • Try to avoid the chained if commands, doing the same stuff – In both get_answer() and print_dice() you have if chains where the block kind of does the same. This is usually an indication that you could find a better way of handling it.

    • In get_answer() I opted for a double ternary, doing answer += 2 if i == 3 else 4 if i == 5 else 0.

    • In print_dice() I used the fact that a six sided die has only 5 distinct patterns, and then I used yet another double ternary to select from the different options.

      _Disclaimer:_ Even though this code is a lot shorter than yours, that doesn't mean it is nicer as such. But it does show an alternate way, and there are multiple ways to print die results. See [here](http://codereview.stackexchange.com/q/111337/78136) or [here](https://codegolf.stackexchange.com/a/2603/45969).
      
  • Use constants, not magic number – Instead of hiding a 5 and an 8 in the code, use constants at top of file like REQUIRED_STREAK_RUN = 8 and NUMBER_OF_DICE = 5. This allows you to change them easily (and you can still make the document reflect the change using str.format()

  • Use str.format() for string formatting - This is a very useful construct, which is well worth some time to look into. You could either use it without names (see end of play_once()), or you could name your variables like in display_help().

    PS! If using Python 2, I recommend using from __future__ import print_function to get the full extent of this beauty there as well.

  • Feature: You can't quit your program without becoming a Pythentate – I think it's nice to give users a way out. I've implemented a lazy version with terminating if entering a negative answer. This could be done a lot nicer, but it should be an option to quit at any time.

  • Using __doc__ to get the docstring for display_help – In Python you can and should describe your code using docstrings, typically text with triple quotes, i.e. """ ... """. These can be used to describe the module, functions, classes (and methods). They typically come on the line after the definition of the item you want to document.

    A neat thing is that this docstring can be accessed using a special variable, __doc__, or for a function as display_help.__doc__. And then it can be used for print outs, or similar.

  • Work a little more on naming methods – It is not very common in Python to have get_xxxx methods, rather name them according to specific function, like roll_multiple_dice() or roll_die(). Aim for simplicity and clarity. Using get_answer() implies that you want me to insert the answer of something, whilst number_of_pythons() indicates that this is going to be calculated.

  • List comprehensions are your friend – Instead of repeating code to build the list, use return [roll_die() for _ in range(number_of_dice)] which implements three nice features:

    1. A list comprehension, which builds a list based on the inner generator, i.e. [ ... ]
    2. The use of for within the generator, x for x in range(y), which compresses a for loop into the expression. This one would return the numbers from 0 to y-1
    3. The use of _ when we don't really care about the number, but just want the code in front of the for loop to be executed
  • Generator expressions – The for loop of last item, can also be used outside of list comprehension, i.e sum(x for x in range(y)), which would sum all the numbers from 0 through y-1.

    One major difference between a list comprehension and generator, is that the list comprehension actually builds the entire list, whilst the generators works in the background and gives you another element when you want it.

    In the sum example this means that if you had y=1000000 you wouldn't allocate memory for more than 1 int, whilst if you used list comprehension you would allocate the entire list of 1 million elements, and then sum it.

  • The Python ternary, i.e. a = b if c else d – This could take some time to get used to, but actually it reads out quite nicely: Set the value of a to b if the condition c is true, or d if not true.

    Disclaimer: In my refactored code this is where it got a little ugly, as I combined multiple of this construction. But still, they kind of make sense. I used them in both number_of_pythons() and print_dice().

  • Avoid one-time intermediate variable – It's quite common to skip the intermediate variable, especially if you use them only once, and rather use the expression directly. I.e. in roll_die() just return the random number, and in roll_multiple_dice() return the list directly.

  • In some cases, you can sum using Booleans – Doing the if True: a += 1 is kind of an anti-pattern, and can in some cases be replaced by a += True, or in your case: streak += play_once(...).

    • Bug found by 200_success: Here the simplification went too far, as I by simply summing, removed the resetting of the streak counter.
  • Avoid flag variables, if possible – Your use of valid in get_guess() is better written using while True and a break like in your input validations. And skipping the intermediate variable, you could return straight out of the loop.

  • Try to avoid the chained if commands, doing the same stuff – In both get_answer() and print_dice() you have if chains where the block kind of does the same. This is usually an indication that you could find a better way of handling it.

    • In get_answer() I opted for a double ternary, doing answer += 2 if i == 3 else 4 if i == 5 else 0.

    • In print_dice() I used the fact that a six sided die has only 5 distinct patterns, and then I used yet another double ternary to select from the different options.

      _Disclaimer:_ Even though this code is a lot shorter than yours, that doesn't mean it is nicer as such. But it does show an alternate way, and there are multiple ways to print die results. See [here](https://codereview.stackexchange.com/q/111337/78136) or [here](https://codegolf.stackexchange.com/a/2603/45969).
      
  • Use constants, not magic number – Instead of hiding a 5 and an 8 in the code, use constants at top of file like REQUIRED_STREAK_RUN = 8 and NUMBER_OF_DICE = 5. This allows you to change them easily (and you can still make the document reflect the change using str.format()

  • Use str.format() for string formatting - This is a very useful construct, which is well worth some time to look into. You could either use it without names (see end of play_once()), or you could name your variables like in display_help().

    PS! If using Python 2, I recommend using from __future__ import print_function to get the full extent of this beauty there as well.

  • Feature: You can't quit your program without becoming a Pythentate – I think it's nice to give users a way out. I've implemented a lazy version with terminating if entering a negative answer. This could be done a lot nicer, but it should be an option to quit at any time.

replaced http://codegolf.stackexchange.com/ with https://codegolf.stackexchange.com/
Source Link
  • Using __doc__ to get the docstring for display_help – In Python you can and should describe your code using docstrings, typically text with triple quotes, i.e. """ ... """. These can be used to describe the module, functions, classes (and methods). They typically come on the line after the definition of the item you want to document.

    A neat thing is that this docstring can be accessed using a special variable, __doc__, or for a function as display_help.__doc__. And then it can be used for print outs, or similar.

  • Work a little more on naming methods – It is not very common in Python to have get_xxxx methods, rather name them according to specific function, like roll_multiple_dice() or roll_die(). Aim for simplicity and clarity. Using get_answer() implies that you want me to insert the answer of something, whilst number_of_pythons() indicates that this is going to be calculated.

  • List comprehensions are your friend – Instead of repeating code to build the list, use return [roll_die() for _ in range(number_of_dice)] which implements three nice features:

    1. A list comprehension, which builds a list based on the inner generator, i.e. [ ... ]
    2. The use of for within the generator, x for x in range(y), which compresses a for loop into the expression. This one would return the numbers from 0 to y-1
    3. The use of _ when we don't really care about the number, but just want the code in front of the for loop to be executed
  • Generator expressions – The for loop of last item, can also be used outside of list comprehension, i.e sum(x for x in range(y)), which would sum all the numbers from 0 through y-1.

    One major difference between a list comprehension and generator, is that the list comprehension actually builds the entire list, whilst the generators works in the background and gives you another element when you want it.

    In the sum example this means that if you had y=1000000 you wouldn't allocate memory for more than 1 int, whilst if you used list comprehension you would allocate the entire list of 1 million elements, and then sum it.

  • The Python ternary, i.e. a = b if c else d – This could take some time to get used to, but actually it reads out quite nicely: Set the value of a to b if the condition c is true, or d if not true.

    Disclaimer: In my refactored code this is where it got a little ugly, as I combined multiple of this construction. But still, they kind of make sense. I used them in both number_of_pythons() and print_dice().

  • Avoid one-time intermediate variable – It's quite common to skip the intermediate variable, especially if you use them only once, and rather use the expression directly. I.e. in roll_die() just return the random number, and in roll_multiple_dice() return the list directly.

  • In some cases, you can sum using Booleans – Doing the if True: a += 1 is kind of an anti-pattern, and can in some cases be replaced by a += True, or in your case: streak += play_once(...).

    • Bug found by 200_success: Here the simplification went too far, as I by simply summing, removed the resetting of the streak counter.
  • Avoid flag variables, if possible – Your use of valid in get_guess() is better written using while True and a break like in your input validations. And skipping the intermediate variable, you could return straight out of the loop.

  • Try to avoid the chained if commands, doing the same stuff – In both get_answer() and print_dice() you have if chains where the block kind of does the same. This is usually an indication that you could find a better way of handling it.

    • In get_answer() I opted for a double ternary, doing answer += 2 if i == 3 else 4 if i == 5 else 0.

    • In print_dice() I used the fact that a six sided die has only 5 distinct patterns, and then I used yet another double ternary to select from the different options.

      _Disclaimer:_ Even though this code is a lot shorter than yours, that doesn't mean it is nicer as such. But it does show an alternate way, and there are multiple ways to print die results. See [here](http://codereview.stackexchange.com/q/111337/78136) or [here](httphttps://codegolf.stackexchange.com/a/2603/45969).
      
  • Use constants, not magic number – Instead of hiding a 5 and an 8 in the code, use constants at top of file like REQUIRED_STREAK_RUN = 8 and NUMBER_OF_DICE = 5. This allows you to change them easily (and you can still make the document reflect the change using str.format()

  • Use str.format() for string formatting - This is a very useful construct, which is well worth some time to look into. You could either use it without names (see end of play_once()), or you could name your variables like in display_help().

    PS! If using Python 2, I recommend using from __future__ import print_function to get the full extent of this beauty there as well.

  • Feature: You can't quit your program without becoming a Pythentate – I think it's nice to give users a way out. I've implemented a lazy version with terminating if entering a negative answer. This could be done a lot nicer, but it should be an option to quit at any time.

  • Using __doc__ to get the docstring for display_help – In Python you can and should describe your code using docstrings, typically text with triple quotes, i.e. """ ... """. These can be used to describe the module, functions, classes (and methods). They typically come on the line after the definition of the item you want to document.

    A neat thing is that this docstring can be accessed using a special variable, __doc__, or for a function as display_help.__doc__. And then it can be used for print outs, or similar.

  • Work a little more on naming methods – It is not very common in Python to have get_xxxx methods, rather name them according to specific function, like roll_multiple_dice() or roll_die(). Aim for simplicity and clarity. Using get_answer() implies that you want me to insert the answer of something, whilst number_of_pythons() indicates that this is going to be calculated.

  • List comprehensions are your friend – Instead of repeating code to build the list, use return [roll_die() for _ in range(number_of_dice)] which implements three nice features:

    1. A list comprehension, which builds a list based on the inner generator, i.e. [ ... ]
    2. The use of for within the generator, x for x in range(y), which compresses a for loop into the expression. This one would return the numbers from 0 to y-1
    3. The use of _ when we don't really care about the number, but just want the code in front of the for loop to be executed
  • Generator expressions – The for loop of last item, can also be used outside of list comprehension, i.e sum(x for x in range(y)), which would sum all the numbers from 0 through y-1.

    One major difference between a list comprehension and generator, is that the list comprehension actually builds the entire list, whilst the generators works in the background and gives you another element when you want it.

    In the sum example this means that if you had y=1000000 you wouldn't allocate memory for more than 1 int, whilst if you used list comprehension you would allocate the entire list of 1 million elements, and then sum it.

  • The Python ternary, i.e. a = b if c else d – This could take some time to get used to, but actually it reads out quite nicely: Set the value of a to b if the condition c is true, or d if not true.

    Disclaimer: In my refactored code this is where it got a little ugly, as I combined multiple of this construction. But still, they kind of make sense. I used them in both number_of_pythons() and print_dice().

  • Avoid one-time intermediate variable – It's quite common to skip the intermediate variable, especially if you use them only once, and rather use the expression directly. I.e. in roll_die() just return the random number, and in roll_multiple_dice() return the list directly.

  • In some cases, you can sum using Booleans – Doing the if True: a += 1 is kind of an anti-pattern, and can in some cases be replaced by a += True, or in your case: streak += play_once(...).

    • Bug found by 200_success: Here the simplification went too far, as I by simply summing, removed the resetting of the streak counter.
  • Avoid flag variables, if possible – Your use of valid in get_guess() is better written using while True and a break like in your input validations. And skipping the intermediate variable, you could return straight out of the loop.

  • Try to avoid the chained if commands, doing the same stuff – In both get_answer() and print_dice() you have if chains where the block kind of does the same. This is usually an indication that you could find a better way of handling it.

    • In get_answer() I opted for a double ternary, doing answer += 2 if i == 3 else 4 if i == 5 else 0.

    • In print_dice() I used the fact that a six sided die has only 5 distinct patterns, and then I used yet another double ternary to select from the different options.

      _Disclaimer:_ Even though this code is a lot shorter than yours, that doesn't mean it is nicer as such. But it does show an alternate way, and there are multiple ways to print die results. See [here](http://codereview.stackexchange.com/q/111337/78136) or [here](http://codegolf.stackexchange.com/a/2603/45969).
      
  • Use constants, not magic number – Instead of hiding a 5 and an 8 in the code, use constants at top of file like REQUIRED_STREAK_RUN = 8 and NUMBER_OF_DICE = 5. This allows you to change them easily (and you can still make the document reflect the change using str.format()

  • Use str.format() for string formatting - This is a very useful construct, which is well worth some time to look into. You could either use it without names (see end of play_once()), or you could name your variables like in display_help().

    PS! If using Python 2, I recommend using from __future__ import print_function to get the full extent of this beauty there as well.

  • Feature: You can't quit your program without becoming a Pythentate – I think it's nice to give users a way out. I've implemented a lazy version with terminating if entering a negative answer. This could be done a lot nicer, but it should be an option to quit at any time.

  • Using __doc__ to get the docstring for display_help – In Python you can and should describe your code using docstrings, typically text with triple quotes, i.e. """ ... """. These can be used to describe the module, functions, classes (and methods). They typically come on the line after the definition of the item you want to document.

    A neat thing is that this docstring can be accessed using a special variable, __doc__, or for a function as display_help.__doc__. And then it can be used for print outs, or similar.

  • Work a little more on naming methods – It is not very common in Python to have get_xxxx methods, rather name them according to specific function, like roll_multiple_dice() or roll_die(). Aim for simplicity and clarity. Using get_answer() implies that you want me to insert the answer of something, whilst number_of_pythons() indicates that this is going to be calculated.

  • List comprehensions are your friend – Instead of repeating code to build the list, use return [roll_die() for _ in range(number_of_dice)] which implements three nice features:

    1. A list comprehension, which builds a list based on the inner generator, i.e. [ ... ]
    2. The use of for within the generator, x for x in range(y), which compresses a for loop into the expression. This one would return the numbers from 0 to y-1
    3. The use of _ when we don't really care about the number, but just want the code in front of the for loop to be executed
  • Generator expressions – The for loop of last item, can also be used outside of list comprehension, i.e sum(x for x in range(y)), which would sum all the numbers from 0 through y-1.

    One major difference between a list comprehension and generator, is that the list comprehension actually builds the entire list, whilst the generators works in the background and gives you another element when you want it.

    In the sum example this means that if you had y=1000000 you wouldn't allocate memory for more than 1 int, whilst if you used list comprehension you would allocate the entire list of 1 million elements, and then sum it.

  • The Python ternary, i.e. a = b if c else d – This could take some time to get used to, but actually it reads out quite nicely: Set the value of a to b if the condition c is true, or d if not true.

    Disclaimer: In my refactored code this is where it got a little ugly, as I combined multiple of this construction. But still, they kind of make sense. I used them in both number_of_pythons() and print_dice().

  • Avoid one-time intermediate variable – It's quite common to skip the intermediate variable, especially if you use them only once, and rather use the expression directly. I.e. in roll_die() just return the random number, and in roll_multiple_dice() return the list directly.

  • In some cases, you can sum using Booleans – Doing the if True: a += 1 is kind of an anti-pattern, and can in some cases be replaced by a += True, or in your case: streak += play_once(...).

    • Bug found by 200_success: Here the simplification went too far, as I by simply summing, removed the resetting of the streak counter.
  • Avoid flag variables, if possible – Your use of valid in get_guess() is better written using while True and a break like in your input validations. And skipping the intermediate variable, you could return straight out of the loop.

  • Try to avoid the chained if commands, doing the same stuff – In both get_answer() and print_dice() you have if chains where the block kind of does the same. This is usually an indication that you could find a better way of handling it.

    • In get_answer() I opted for a double ternary, doing answer += 2 if i == 3 else 4 if i == 5 else 0.

    • In print_dice() I used the fact that a six sided die has only 5 distinct patterns, and then I used yet another double ternary to select from the different options.

      _Disclaimer:_ Even though this code is a lot shorter than yours, that doesn't mean it is nicer as such. But it does show an alternate way, and there are multiple ways to print die results. See [here](http://codereview.stackexchange.com/q/111337/78136) or [here](https://codegolf.stackexchange.com/a/2603/45969).
      
  • Use constants, not magic number – Instead of hiding a 5 and an 8 in the code, use constants at top of file like REQUIRED_STREAK_RUN = 8 and NUMBER_OF_DICE = 5. This allows you to change them easily (and you can still make the document reflect the change using str.format()

  • Use str.format() for string formatting - This is a very useful construct, which is well worth some time to look into. You could either use it without names (see end of play_once()), or you could name your variables like in display_help().

    PS! If using Python 2, I recommend using from __future__ import print_function to get the full extent of this beauty there as well.

  • Feature: You can't quit your program without becoming a Pythentate – I think it's nice to give users a way out. I've implemented a lazy version with terminating if entering a negative answer. This could be done a lot nicer, but it should be an option to quit at any time.

deleted 1 character in body
Source Link
TheCoffeeCup
  • 9.5k
  • 4
  • 38
  • 96

In general your code looks nice, but it does show that you've got a another programming language background, and thuslythus you do it the standard imperative way instead of utilizing some of the more pythonic way. In this review I'm deliberately going a little over the top, but in return you get to see some of the more special pythonic constructions.

  • Using __doc__ to get the docstring for display_help – In Python you can and should describe your code using docstrings, typically text with triple quotes, i.e. """ ... """""" ... """. These can be used to describe the module, functions, classes (and methods). They typically come on the line after the definition of the item you want to document.

    A neat thingything is that this docstring can be accessed using a special variable, __doc__, or for a function as display_help.__doc__. And then it can be used for print outs, or similar.

  • Work a little more on naming methods – It is not very common in Python to have get_xxxx methods, rather name them according to specific function, like roll_multiple_dice() or roll_die(). Aim for simplicity and clarity. Using get_answer() implies that you want me to insert the answer of something, whilst number_of_pythons() indicates that this is going to be calculated.

  • List comprehensions are your friend – Instead of repeating code to build the list, use return [roll_die() for _ in range(number_of_dice)] which implements three nice features:

    1. A list comprehension, which builds a list based on the inner generator, i.e. [ ... ]
    2. The use of for within the generator, x for x in range(y), which compresses a for loop into the expression. This one would return the numbers from 0 to y-1
    3. The use of _ when we don't really care about the number, but just want the code in front of the for loop to be executed
  • Generator expressions – The for loop of last item, can also be used outside of list comprehension, i.e sum(x for x in range(y)), which would sum all the numbers from 0 through y-1.

    One major difference between a list comprehension and generator, is that the list comprehension actually builds the entire list, whilst the generators works in the background and gives you another element when you want it.

    In the sum example this means that if you had y=1000000 you wouldn't allocate memory for more than 1 int, whilst if you used list comprehension you would allocate the entire list of 1 million elements, and then sum it.

  • The Python ternary, i.e. a = b if c else d – This could take some time to get used to, but actually it reads out quite nicely: Set the value of a to b if the condition c is true, or d if not true.

    Disclaimer: In my refactored code this is where it got a little ugly, as I combined multiple of this construction. But still, they kind of make sense. I used them in both number_of_pythons() and print_dice().

  • Avoid one-time intermediate variable – It's quite common to skip the intermediate variable, especially if you use them only once, and rather use the expression directly. I.e. in roll_die() just return the random number, and in roll_multiple_dice() return the list directly.

  • In some cases, you can sum using Booleans – Doing the if True: a += 1 is kind of an anti-pattern, and can in some cases be replaced by a += True, or in your case: streak += play_once(...).

    • Bug found by 200_success: Here the simplification went too far, as I by simply summing, removed the resetting of the streak counter.
  • Avoid flag variables, if possible – Your use of valid in get_guess() is better written using while True and a break like in your input validations. And skipping the intermediate variable, you could return straight out of the loop.

  • Try to avoid the chained if commands, doing the same stuff – In both get_answer() and print_dice() you have if chains where the block kind of does the same. This is usually an indication that you could find a better way of handling it.

    • In get_answer() I opted for a double ternary, doing answer += 2 if i == 3 else 4 if i == 5 else 0.

    • In print_dice() I used the fact that a six sided die has only 5 distinct patterns, and then I used yet another double ternary to select from the different options.

      _Disclaimer:_ Even though this code is a lot shorter than yours, that doesn't mean it is nicer as such. But it does show an alternate way, and there are multiple ways to print die results. See [here](http://codereview.stackexchange.com/q/111337/78136) or [here](http://codegolf.stackexchange.com/a/2603/45969).
      
  • Use constants, not magic number – Instead of hiding a 5 and an 8 in the code, use constants at top of file like REQUIRED_STREAK_RUN = 8 and NUMBER_OF_DICE = 5. This allows you to change them easily (and you can still make the document reflect the change using str.format()

  • Use str.format() for string formatting - This is a very useful construct, which is well worth some time to look into. You could either use it without names (see end of play_once()), or you could name your variables like in display_help().

    PS! If using Python 2, I recommend using from __future__ import print_function to get the full extent of this beauty there as well.

  • Feature: You can't quit your program without becoming a Pythentate – I think it's nice to give users a way out. I've implemented a lazy version with terminating if entering a negative answer. This could be done a lot nicer, but it should be an option to quit at any time.

In general your code looks nice, but it does show that you've got a another programming language background, and thusly you do it the standard imperative way instead of utilizing some of the more pythonic way. In this review I'm deliberately going a little over the top, but in return you get to see some of the more special pythonic constructions.

  • Using __doc__ to get the docstring for display_help – In Python you can and should describe your code using docstrings, typically text with triple quotes, i.e. """ ... """. These can be used to describe the module, functions, classes (and methods). They typically come on the line after the definition of the item you want to document.

    A neat thingy is that this docstring can be accessed using a special variable, __doc__, or for a function as display_help.__doc__. And then it can be used for print outs, or similar.

  • Work a little more on naming methods – It is not very common in Python to have get_xxxx methods, rather name them according to specific function, like roll_multiple_dice() or roll_die(). Aim for simplicity and clarity. Using get_answer() implies that you want me to insert the answer of something, whilst number_of_pythons() indicates that this is going to be calculated.

  • List comprehensions are your friend – Instead of repeating code to build the list, use return [roll_die() for _ in range(number_of_dice)] which implements three nice features:

    1. A list comprehension, which builds a list based on the inner generator, i.e. [ ... ]
    2. The use of for within the generator, x for x in range(y), which compresses a for loop into the expression. This one would return the numbers from 0 to y-1
    3. The use of _ when we don't really care about the number, but just want the code in front of the for loop to be executed
  • Generator expressions – The for loop of last item, can also be used outside of list comprehension, i.e sum(x for x in range(y)), which would sum all the numbers from 0 through y-1.

    One major difference between a list comprehension and generator, is that the list comprehension actually builds the entire list, whilst the generators works in the background and gives you another element when you want it.

    In the sum example this means that if you had y=1000000 you wouldn't allocate memory for more than 1 int, whilst if you used list comprehension you would allocate the entire list of 1 million elements, and then sum it.

  • The Python ternary, i.e. a = b if c else d – This could take some time to get used to, but actually it reads out quite nicely: Set the value of a to b if the condition c is true, or d if not true.

    Disclaimer: In my refactored code this is where it got a little ugly, as I combined multiple of this construction. But still, they kind of make sense. I used them in both number_of_pythons() and print_dice().

  • Avoid one-time intermediate variable – It's quite common to skip the intermediate variable, especially if you use them only once, and rather use the expression directly. I.e. in roll_die() just return the random number, and in roll_multiple_dice() return the list directly.

  • In some cases, you can sum using Booleans – Doing the if True: a += 1 is kind of an anti-pattern, and can in some cases be replaced by a += True, or in your case: streak += play_once(...).

    • Bug found by 200_success: Here the simplification went too far, as I by simply summing, removed the resetting of the streak counter.
  • Avoid flag variables, if possible – Your use of valid in get_guess() is better written using while True and a break like in your input validations. And skipping the intermediate variable, you could return straight out of the loop.

  • Try to avoid the chained if commands, doing the same stuff – In both get_answer() and print_dice() you have if chains where the block kind of does the same. This is usually an indication that you could find a better way of handling it.

    • In get_answer() I opted for a double ternary, doing answer += 2 if i == 3 else 4 if i == 5 else 0.

    • In print_dice() I used the fact that a six sided die has only 5 distinct patterns, and then I used yet another double ternary to select from the different options.

      _Disclaimer:_ Even though this code is a lot shorter than yours, that doesn't mean it is nicer as such. But it does show an alternate way, and there are multiple ways to print die results. See [here](http://codereview.stackexchange.com/q/111337/78136) or [here](http://codegolf.stackexchange.com/a/2603/45969).
      
  • Use constants, not magic number – Instead of hiding a 5 and an 8 in the code, use constants at top of file like REQUIRED_STREAK_RUN = 8 and NUMBER_OF_DICE = 5. This allows you to change them easily (and you can still make the document reflect the change using str.format()

  • Use str.format() for string formatting - This is a very useful construct, which is well worth some time to look into. You could either use it without names (see end of play_once()), or you could name your variables like in display_help().

    PS! If using Python 2, I recommend using from __future__ import print_function to get the full extent of this beauty there as well.

  • Feature: You can't quit your program without becoming a Pythentate – I think it's nice to give users a way out. I've implemented a lazy version with terminating if entering a negative answer. This could be done a lot nicer, but it should be an option to quit at any time.

In general your code looks nice, but it does show that you've got a another programming language background, and thus you do it the standard imperative way instead of utilizing some of the more pythonic way. In this review I'm deliberately going a little over the top, but in return you get to see some of the more special pythonic constructions.

  • Using __doc__ to get the docstring for display_help – In Python you can and should describe your code using docstrings, typically text with triple quotes, i.e. """ ... """. These can be used to describe the module, functions, classes (and methods). They typically come on the line after the definition of the item you want to document.

    A neat thing is that this docstring can be accessed using a special variable, __doc__, or for a function as display_help.__doc__. And then it can be used for print outs, or similar.

  • Work a little more on naming methods – It is not very common in Python to have get_xxxx methods, rather name them according to specific function, like roll_multiple_dice() or roll_die(). Aim for simplicity and clarity. Using get_answer() implies that you want me to insert the answer of something, whilst number_of_pythons() indicates that this is going to be calculated.

  • List comprehensions are your friend – Instead of repeating code to build the list, use return [roll_die() for _ in range(number_of_dice)] which implements three nice features:

    1. A list comprehension, which builds a list based on the inner generator, i.e. [ ... ]
    2. The use of for within the generator, x for x in range(y), which compresses a for loop into the expression. This one would return the numbers from 0 to y-1
    3. The use of _ when we don't really care about the number, but just want the code in front of the for loop to be executed
  • Generator expressions – The for loop of last item, can also be used outside of list comprehension, i.e sum(x for x in range(y)), which would sum all the numbers from 0 through y-1.

    One major difference between a list comprehension and generator, is that the list comprehension actually builds the entire list, whilst the generators works in the background and gives you another element when you want it.

    In the sum example this means that if you had y=1000000 you wouldn't allocate memory for more than 1 int, whilst if you used list comprehension you would allocate the entire list of 1 million elements, and then sum it.

  • The Python ternary, i.e. a = b if c else d – This could take some time to get used to, but actually it reads out quite nicely: Set the value of a to b if the condition c is true, or d if not true.

    Disclaimer: In my refactored code this is where it got a little ugly, as I combined multiple of this construction. But still, they kind of make sense. I used them in both number_of_pythons() and print_dice().

  • Avoid one-time intermediate variable – It's quite common to skip the intermediate variable, especially if you use them only once, and rather use the expression directly. I.e. in roll_die() just return the random number, and in roll_multiple_dice() return the list directly.

  • In some cases, you can sum using Booleans – Doing the if True: a += 1 is kind of an anti-pattern, and can in some cases be replaced by a += True, or in your case: streak += play_once(...).

    • Bug found by 200_success: Here the simplification went too far, as I by simply summing, removed the resetting of the streak counter.
  • Avoid flag variables, if possible – Your use of valid in get_guess() is better written using while True and a break like in your input validations. And skipping the intermediate variable, you could return straight out of the loop.

  • Try to avoid the chained if commands, doing the same stuff – In both get_answer() and print_dice() you have if chains where the block kind of does the same. This is usually an indication that you could find a better way of handling it.

    • In get_answer() I opted for a double ternary, doing answer += 2 if i == 3 else 4 if i == 5 else 0.

    • In print_dice() I used the fact that a six sided die has only 5 distinct patterns, and then I used yet another double ternary to select from the different options.

      _Disclaimer:_ Even though this code is a lot shorter than yours, that doesn't mean it is nicer as such. But it does show an alternate way, and there are multiple ways to print die results. See [here](http://codereview.stackexchange.com/q/111337/78136) or [here](http://codegolf.stackexchange.com/a/2603/45969).
      
  • Use constants, not magic number – Instead of hiding a 5 and an 8 in the code, use constants at top of file like REQUIRED_STREAK_RUN = 8 and NUMBER_OF_DICE = 5. This allows you to change them easily (and you can still make the document reflect the change using str.format()

  • Use str.format() for string formatting - This is a very useful construct, which is well worth some time to look into. You could either use it without names (see end of play_once()), or you could name your variables like in display_help().

    PS! If using Python 2, I recommend using from __future__ import print_function to get the full extent of this beauty there as well.

  • Feature: You can't quit your program without becoming a Pythentate – I think it's nice to give users a way out. I've implemented a lazy version with terminating if entering a negative answer. This could be done a lot nicer, but it should be an option to quit at any time.

Corrected bug I introduced, mentioned by 200_success
Source Link
holroy
  • 11.8k
  • 1
  • 27
  • 59
Loading
Source Link
holroy
  • 11.8k
  • 1
  • 27
  • 59
Loading