Skip to main content
fix link
Source Link
ShapeOfMatter
  • 4.3k
  • 6
  • 25

You've done a great job demoing a variety of patterns and tools. I'll add two more things you could benefit from learning early:

  • Type hints. Function headers are almost always clearer with type hints, and you need them if you want to use a tool like MyPy.
  • The main method patternThe main method pattern.
  • (Usually I'd also advocate for recursion when someone's demo project is a REPL game like this, but in your case I don't think it would improve this code.)

Other stuff:

  • Usually it's better to avoid exceptions when you have other options. While you could do what you're doing here by other means, you've done a few things that make me like your check function: It's concise, it bundles away a discrete bit of functionality, and you're catching a narrowly defined exception class.
  • Unfortunately, it's a little clunky to have a function that just tells you if int(x) threw an exception, just so you can call int(x) on the next line. You have many other options; I'd be fine with def check (user_input: str) -> Optional[int]:..., but then you must use if x is [not] None:... later.
  • Depending exactly what the function in question does, either validate or sanitize would probably be better than check.
  • I lied: another new thing to learn: itertools. In particular, a while loop that increments something is always begging to get replaced with a for loop. In this case, since we want to keep going "as long as it takes", we need a lazy infinite iteratable: itertools.count(0).
    • In order to make that work, we'll need to separate out the "that input was invalid, try again" logic into a separate loop (or recursive function).
    • And then if you teach yourself generators you could write for (try_number, user_input) in zip(itertools.count(0), yielded_user_input()):.... Fun times!

You've done a great job demoing a variety of patterns and tools. I'll add two more things you could benefit from learning early:

  • Type hints. Function headers are almost always clearer with type hints, and you need them if you want to use a tool like MyPy.
  • The main method pattern.
  • (Usually I'd also advocate for recursion when someone's demo project is a REPL game like this, but in your case I don't think it would improve this code.)

Other stuff:

  • Usually it's better to avoid exceptions when you have other options. While you could do what you're doing here by other means, you've done a few things that make me like your check function: It's concise, it bundles away a discrete bit of functionality, and you're catching a narrowly defined exception class.
  • Unfortunately, it's a little clunky to have a function that just tells you if int(x) threw an exception, just so you can call int(x) on the next line. You have many other options; I'd be fine with def check (user_input: str) -> Optional[int]:..., but then you must use if x is [not] None:... later.
  • Depending exactly what the function in question does, either validate or sanitize would probably be better than check.
  • I lied: another new thing to learn: itertools. In particular, a while loop that increments something is always begging to get replaced with a for loop. In this case, since we want to keep going "as long as it takes", we need a lazy infinite iteratable: itertools.count(0).
    • In order to make that work, we'll need to separate out the "that input was invalid, try again" logic into a separate loop (or recursive function).
    • And then if you teach yourself generators you could write for (try_number, user_input) in zip(itertools.count(0), yielded_user_input()):.... Fun times!

You've done a great job demoing a variety of patterns and tools. I'll add two more things you could benefit from learning early:

  • Type hints. Function headers are almost always clearer with type hints, and you need them if you want to use a tool like MyPy.
  • The main method pattern.
  • (Usually I'd also advocate for recursion when someone's demo project is a REPL game like this, but in your case I don't think it would improve this code.)

Other stuff:

  • Usually it's better to avoid exceptions when you have other options. While you could do what you're doing here by other means, you've done a few things that make me like your check function: It's concise, it bundles away a discrete bit of functionality, and you're catching a narrowly defined exception class.
  • Unfortunately, it's a little clunky to have a function that just tells you if int(x) threw an exception, just so you can call int(x) on the next line. You have many other options; I'd be fine with def check (user_input: str) -> Optional[int]:..., but then you must use if x is [not] None:... later.
  • Depending exactly what the function in question does, either validate or sanitize would probably be better than check.
  • I lied: another new thing to learn: itertools. In particular, a while loop that increments something is always begging to get replaced with a for loop. In this case, since we want to keep going "as long as it takes", we need a lazy infinite iteratable: itertools.count(0).
    • In order to make that work, we'll need to separate out the "that input was invalid, try again" logic into a separate loop (or recursive function).
    • And then if you teach yourself generators you could write for (try_number, user_input) in zip(itertools.count(0), yielded_user_input()):.... Fun times!
Source Link
ShapeOfMatter
  • 4.3k
  • 6
  • 25

You've done a great job demoing a variety of patterns and tools. I'll add two more things you could benefit from learning early:

  • Type hints. Function headers are almost always clearer with type hints, and you need them if you want to use a tool like MyPy.
  • The main method pattern.
  • (Usually I'd also advocate for recursion when someone's demo project is a REPL game like this, but in your case I don't think it would improve this code.)

Other stuff:

  • Usually it's better to avoid exceptions when you have other options. While you could do what you're doing here by other means, you've done a few things that make me like your check function: It's concise, it bundles away a discrete bit of functionality, and you're catching a narrowly defined exception class.
  • Unfortunately, it's a little clunky to have a function that just tells you if int(x) threw an exception, just so you can call int(x) on the next line. You have many other options; I'd be fine with def check (user_input: str) -> Optional[int]:..., but then you must use if x is [not] None:... later.
  • Depending exactly what the function in question does, either validate or sanitize would probably be better than check.
  • I lied: another new thing to learn: itertools. In particular, a while loop that increments something is always begging to get replaced with a for loop. In this case, since we want to keep going "as long as it takes", we need a lazy infinite iteratable: itertools.count(0).
    • In order to make that work, we'll need to separate out the "that input was invalid, try again" logic into a separate loop (or recursive function).
    • And then if you teach yourself generators you could write for (try_number, user_input) in zip(itertools.count(0), yielded_user_input()):.... Fun times!