How can you pass values to a function without naming every parameter? Use positional arguments. Python matches each unnamed value to a parameter according to its place in the call, so order matters. section 6.4.1
Call a function by position
For `def multiply_numbers(a, b): return a * b`, the call `multiply_numbers(3, 4)` assigns `3` to `a` and `4` to `b`, returning `12`. You can instead write `multiply_numbers(b=4, a=3)`: keyword arguments match by name, so their order does not matter. In a mixed call such as `multiply_numbers(3, b=4)`, put positional arguments first; reversing that order raises a `SyntaxError`. section 6.4.1
Accept any number of positional arguments
Define `stringify(*items)` to accept zero or more positional values. Inside the function, `items` is a tuple: `stringify(1, "two", None)` receives `(1, 'two', None)` and can return `['1', 'two', 'None']` using `[str(item) for item in items]`. If a function also needs a required positional parameter, place it before `*items`: in `def stringify_a(item0, *items)`, the first value goes to `item0` and the rest form the tuple. section 6.4.2
Keep calls easy to read:
- Prefer explicitly named parameters when the number of inputs is known. Use `*args` when the number of positional values cannot be known in advance; flexibility makes the accepted inputs less explicit. section 6.4.4
- For a constructor, put important required inputs first, but limit positional inputs when readers might struggle to tell them apart. Additional inputs can be keyword-only. section 8.1.2
Construct an object
With `Task.__init__(self, title, desc, urgency)`, `Task("Laundry", "Wash clothes", 3)` assigns those three values to `title`, `desc`, and `urgency` in order. This is concise when each position is clear; a long run of unnamed values is harder to interpret. section 8.1.2


