Real programs need a way to receive information from the person running them. Python provides two complementary channels: input() for interactive, prompt-driven data entry, and sys.argv for values supplied on the command line when the script starts. Most scripts eventually use both — command-line arguments for options that rarely change, and input() for answers you want the user to confirm in the terminal.
The critical fact about input() is that it always returns a string, even when the user types digits. Forgetting this is the single most common first-week bug: age = input("age? ") followed by age + 1 raises TypeError: can only concatenate str (not "int") to str. The fix is an explicit conversion with int() or float(), wrapped in a try/except ValueError block so that non-numeric input becomes a readable error instead of a crash.
sys.argv is a list of strings; the first element is the script name, so real arguments start at sys.argv[1]. For anything more than a single optional argument, reach for the argparse module, which is in the standard library and produces automatic --help text, type conversion, default values and informative error messages. Adopting argparse early saves rewriting the same manual argument parsing every project.
Validation is the other half of input handling. Always assume the text could be empty, contain leading or trailing whitespace, mix case, or be outside the expected range. Strip whitespace with .strip(), normalise case with .lower(), compare against an explicit whitelist, and check numeric ranges with plain if statements. A forgiving program validates once, reports clearly, and keeps going.
When input comes from a file or another process rather than a human, do not use input(). Read from sys.stdin directly with a loop (for line in sys.stdin) or open a file. This keeps the same logic working whether the script is invoked interactively or in a pipeline. For secrets (passwords), use getpass.getpass() which hides the typed characters; for long-running prompts with history and autocompletion, use the readline module or prompt_toolkit.
Converting and validating one value at a time
Wrap the conversion in a small helper so the main loop stays readable. A typical pattern is: read the string, strip whitespace, attempt conversion, and on failure print a helpful message and ask again. Looping until the answer is valid is the clearest behaviour for short scripts; raising an exception is more appropriate when the input is non-interactive.
Command-line arguments with argparse
The minimum useful argparse setup is four lines: create a parser, add_argument for each flag, call parse_args(), then use the attributes it returns. Positional arguments are required by default; options prefixed with -- are optional and can have defaults. Adding type=int or type=pathlib.Path performs conversion for you and produces a helpful error on bad input.
These are the tools you will reach for whenever a script needs to read information it did not already have.
| Tool | Purpose |
|---|---|
input()built-in | Reads one line from the keyboard and returns it as a string. |
int()built-in | Converts a string or number to an integer, raises ValueError. |
float()built-in | Converts to a floating-point number. |
sys.argvattribute | List of command-line arguments; [0] is the script name. |
argparsestandard-library module | Declarative parser for command-line options and positional args. |
sys.stdinfile object | Stream used when input is piped from another program. |
getpass.getpass()function | Prompts for a value without echoing it to the screen. |
try / except ValueErrorstatement | Converts a failed int()/float() into a readable error. |
Accepting User Input code example
The script asks for a number interactively but also accepts one from the command line, so it works in both modes without extra flags.
# Lesson: Accepting User Input
# Run interactively: python age.py
# Run with an argument: python age.py 42
import sys
def parse_age(raw: str) -> int:
'''Return a clean integer age or raise ValueError with a readable message.'''
text = raw.strip()
if not text:
raise ValueError("age must not be empty")
value = int(text) # raises ValueError on "twelve", "1.5", etc.
if not 0 <= value <= 150:
raise ValueError(f"age {value} is outside the sensible range 0..150")
return value
def ask_for_age(prompt: str = "Your age? ") -> int:
'''Loop until the user types something convertible.'''
while True:
try:
return parse_age(input(prompt))
except ValueError as err:
print(f"sorry: {err}. Try again.")
def main(argv: list[str]) -> int:
if len(argv) > 1: # command-line mode
age = parse_age(argv[1])
else: # interactive mode
age = ask_for_age()
print(f"next year you will be {age + 1}.")
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv))
Read the script so each responsibility lives in one place:
1) parse_age() is pure: no prompts, no loops, just string -> int.
2) ask_for_age() handles interactive retries by catching ValueError.
3) main() decides which mode to run based on the number of arguments.
4) The script can still be imported; main() runs only under __main__.
Two short snippets practising argparse and piped input.
# Example A: argparse for a tiny calculator
import argparse
parser = argparse.ArgumentParser(description="Add two numbers.")
parser.add_argument("a", type=float)
parser.add_argument("b", type=float)
parser.add_argument("--round", type=int, default=2)
args = parser.parse_args(["1.5", "2.75", "--round", "1"])
print(round(args.a + args.b, args.round)) # -> 4.2
# Example B: read a whole pipe of numbers from stdin
# echo -e "1\n2\n3" | python sum_stdin.py
import sys
numbers = [int(line) for line in sys.stdin.read().split() if line.strip()]
print(sum(numbers))
Validate the parser directly so the core rule is not tied to the prompt.
assert parse_age(" 21 ") == 21
for bad in ["", "nope", "-1", "200", "3.2"]:
try:
parse_age(bad)
except ValueError:
continue
raise AssertionError(f"{bad!r} should have raised ValueError")
A sample interactive session:
Your age? twelve
sorry: invalid literal for int() with base 10: 'twelve'. Try again.
Your age? 41
next year you will be 42.