AlgoMaster Logo

Function Parameters

High Priority22 min readUpdated June 6, 2026
Listen to this chapter
Unlock Audio

When you call a function, the values you pass at the call site have to line up with the names declared in the function header. Python gives you two ways to make that connection (by position and by name), plus syntax to force callers into one mode or the other. This lesson covers what each piece does, when each one matters, and the exact error messages you'll see when the wiring goes wrong.

Parameter vs Argument

These two words get used interchangeably in casual conversation, but Python's error messages care about the difference, and so should you.

A parameter is the name in the function definition. It's a label that lives inside the function body. An argument is the value you pass at the call site when you invoke the function. Same connection, two ends, two words.

In the def line, customer, item, and quantity are parameters. At the call site, "Alice", "Wireless Mouse", and 2 are arguments. The parameters are the slots, the arguments are what you put in them.

This split shows up clearly in Python's tracebacks. When something goes wrong, Python tells you which side of the wall the problem is on. If a parameter has no matching argument, the error mentions the missing argument. If you pass an argument with a name that doesn't exist as a parameter, the error mentions the unexpected keyword argument.

Python identifies quantity by its parameter name and labels it a "required positional argument". You'll see this exact shape of error several more times in this lesson. Read it carefully each time: the parameter name and the word "argument" together tell you which slot didn't get filled.

There's one more piece of vocabulary worth pinning down now: a call signature (or just signature) is the part of the function definition that lists the parameters. For place_order above, the signature is (customer, item, quantity). When we discuss positional-only and keyword-only parameters later, we'll be talking about syntax that goes inside the signature.

Positional Arguments

A positional argument is an argument that binds to a parameter by position: the first argument goes to the first parameter, the second to the second, and so on. This is what you've been writing whenever you've called a function without naming the parameters at the call site.

"Alice" lines up with customer because both are first. "Wireless Mouse" lines up with item because both are second. 2 lines up with quantity because both are third. The order at the call site has to match the order in the def header.

This works because Python walks through the parameters left to right and assigns the arguments in the order they appear. There's no name-matching happening at this point; it's pure position.

The arrows show the binding. Position 1 in the call goes to position 1 in the definition, and so on. Nothing else affects the wiring.

Because order is everything, swapping two positional arguments produces silent bugs whenever the types line up. Watch what happens when quantity and a price-like number get swapped.

No error. The function ran. The output is nonsense, but Python had no way to know that, because "Wireless Mouse" and "Alice" are both strings and the function takes any string for customer and item. This is the classic argument for using keyword arguments (next section) when a call has more than a few positional values that share a type.

A second classic problem is passing too many positional arguments. Python catches this at call time.

The error names the count, not the values, because Python doesn't know which of the three you meant to drop. It's your call to figure out which one is extra.

The mirror of that error, passing too few, gives missing 1 required positional argument: 'quantity'. Same idea, opposite direction.

Keyword Arguments

A keyword argument binds to a parameter by name, not by position. You write name=value at the call site, and Python looks up name among the parameters and puts value there.

The result is identical to the positional version, but the wiring is different. Python isn't counting positions here; it's reading the names. That has two practical consequences.

First, order at the call site stops mattering. As long as every required parameter gets a value, you can write the keyword arguments in any order you want.

Both calls produce the right output even though the arguments are written in different orders. Python looks at the names, not the positions.

Second, call sites become self-documenting. If you're reading code that says place_order("Bob", "USB Cable", 3), you have to remember the parameter order to know which value means what. If you're reading place_order(customer="Bob", item="USB Cable", quantity=3), no memory is required. The names are right there.

Keyword arguments also turn the silent swap bug from earlier into an explicit one. If you accidentally write place_order(customer="Wireless Mouse", item="Bob", quantity=2), the function still runs (the names match), but the values are obviously wrong when you read the call site, because the parameter names tell you what each value is supposed to be.

There's one error specific to keyword arguments: passing a keyword that isn't actually a parameter name.

The function has a parameter called item, not product. Python catches the mismatch at call time and tells you exactly which keyword it didn't recognize. The fix is to use the actual parameter name (item=...) or to rename the parameter in the function definition if product is the better label.

Mixing Positional and Keyword Arguments

Python lets you mix the two styles in a single call, with one rule: positional arguments come first, keyword arguments come after. Once you write a keyword argument, every argument after it has to also be a keyword argument.

In the first call, two positional arguments fill customer and item, then quantity=2 fills the third slot by name. In the second call, one positional argument fills customer, then two keyword arguments fill the rest. Both are fine.

Reversing the order isn't fine. A positional argument after a keyword argument is a syntax error, caught before the program even runs.

The 2 is positional, and it appears after the keyword argument item="Wireless Mouse". Python flags this at parse time, which is why the traceback shows SyntaxError instead of TypeError. The fix is to either move the 2 before the keyword arguments or to pass it by name as quantity=2.

The other mistake this section introduces is passing the same parameter twice, once positionally and once by name. This happens when you mean to add a keyword argument but forget that the same slot is already filled positionally.

The first positional argument "Alice" already filled customer. The keyword argument customer="Bob" tries to fill the same slot again. Python refuses to pick one. This error tends to show up after a refactor where a function's parameter order changes and one call site doesn't get updated cleanly.

A common style guideline (used by many style guides and seen in popular libraries) is: pass the first one or two values positionally when their meaning is obvious from context, and pass the rest by keyword. For place_order("Alice", item="Wireless Mouse", quantity=2), the customer is clearly Alice from context, but item and quantity benefit from the explicit labels. This isn't a hard rule; it's a habit that scales well as functions grow.

Positional-Only Parameters with /

Sometimes you don't want callers to use keyword syntax for certain parameters. Maybe the parameter name is an implementation detail and you want the freedom to rename it later without breaking anyone's code. Maybe the parameter name is so generic that letting callers reference it by name is just noise. For those cases, Python 3.8 added the / marker, which says "everything before this / can only be passed positionally".

The / is not a parameter. It's a marker in the parameter list. Everything to the left of it (price and percent here) is positional-only. Trying to call this function with keyword syntax fails.

The error message is specific: positional-only arguments were passed as keywords. The parameter names exist in the source code, but they're not part of the function's public contract. Python's own built-ins lean on this heavily. len(obj) is positional-only; you can't call len(obj=some_list). Same for print with its first positional values, and many methods on built-in types.

The shape of a /-using signature deserves a small picture. Anything on the left of / is locked to positional. Anything on the right behaves normally (positional or keyword, your choice).

The orange box on the left is the positional-only zone; the cyan box on the right is the normal zone. The red / is the divider. You can freely choose how to pass the cyan parameters, but the orange ones must come in by position.

Here's a mixed example.

Both calls work. customer and item are locked to positional (left of /), and quantity is free to be either. But this call fails:

The reasons you'd use / in your own code are narrow. The two most common ones: the parameter name is meaningless ("the value to operate on", "the input"), or you genuinely want the freedom to rename the parameter without breaking callers. For most application code, you won't need it. For library code that exposes a stable API, it's a useful tool.

Keyword-Only Parameters with *

The mirror of / is *. A bare * in the parameter list says "everything after this * can only be passed by keyword". The motivation is the opposite of /: instead of hiding a parameter name, you're requiring the caller to use it, because the name carries information that a position wouldn't convey.

The first parameter price is normal (positional or keyword). The * marker comes next. Then percent, which is keyword-only because of where it sits. Calling this function with percent passed positionally fails.

Python's count of "positional arguments" only includes the parameters that can be passed positionally. Since percent is keyword-only, the function "takes 1 positional argument" (just price), and passing two positionals is one too many.

The classic reason to use * is to make a function call read clearly when it has a value that would otherwise be a mystery number or boolean. Consider an order placement that takes a flag for whether to send a confirmation email.

Without *, a caller could write place_order("Alice", "Wireless Mouse", 2, True). The reader has to look up the function to find out what that trailing True means. With *, the only way to write the call is send_email=True, and the meaning is right there. This pattern is common in library APIs: any boolean flag or rarely-used option tends to be keyword-only.

There's a second, more practical reason: if you reorder or insert keyword-only parameters later, no caller breaks. Positional callers care about order; keyword callers don't. Locking a parameter to keyword-only is a small commitment that buys you flexibility for the lifetime of the function.

The cyan zone on the left is flexible; the orange zone on the right is locked to keyword. The red * is the marker.

A note on the bare * versus *args: *args is a star followed by a parameter name and it collects any extra positional arguments. The bare * here has no name, collects nothing, and only acts as a divider. Same character, different role.

Combining / and * in One Signature

/ and * can appear in the same parameter list, and when they do they carve the parameters into three zones: positional-only on the left of /, normal (positional or keyword) in the middle, and keyword-only on the right of *.

customer and item are positional-only (left of /). quantity is in the middle zone and can be either. send_email is keyword-only (right of *).

Three zones, two markers. The orange zone is locked to positional, the teal zone is locked to keyword, and the cyan zone in the middle accepts either style. This is the complete picture of how a parameter list is shaped in modern Python.

If you try to pass a positional-only parameter as a keyword, you get the error from the / section. If you try to pass a keyword-only parameter as a positional, you get the error from the * section. Both rules apply to the same call, separately.

Two of the four arguments (customer and item) are in the positional-only zone, and the call tried to pass them as keywords. The error names exactly those two.

The function has three positional-friendly parameters (customer, item, quantity), and the call passed four positional values. The fourth would have to be a keyword argument, because send_email is keyword-only.

You won't reach for this combined shape often in everyday code. Most application functions get by with normal parameters. The pattern shows up in library APIs where the author wants to lock down the public contract precisely. When you do see it, the rule to remember is: / says "stop using names here", * says "start using names here", and anything between them gets to choose.

Common Errors Reference

The errors you've seen scattered through this lesson are the four you'll meet most often. They're worth seeing side by side, with the exact wording Python uses, because the wording tells you which rule was broken.

What you did wrongError you'll see
Forgot a required argumentTypeError: f() missing 1 required positional argument: 'x'
Passed too many positional argumentsTypeError: f() takes N positional arguments but M were given
Used a keyword that isn't a parameterTypeError: f() got an unexpected keyword argument 'x'
Filled the same slot twiceTypeError: f() got multiple values for argument 'x'
Wrote positional after keywordSyntaxError: positional argument follows keyword argument
Used keyword for a positional-only parameterTypeError: f() got some positional-only arguments passed as keyword: 'x'

The first four are runtime errors (TypeError): Python notices them when the call actually happens. The fifth is a parse-time error (SyntaxError): Python rejects the source file before any code runs. The sixth is a runtime error specific to /.

When you see one of these in a traceback, the recipe is the same every time:

  1. Read the function's def line.
  2. Read your call site.
  3. Match them up parameter by parameter, in order, then by name.
  4. The mismatch the error names is where the gap is.

This is more useful than it sounds. Most of the time the fix is obvious once you've actually compared the two sides; the error message just nudges you to do that comparison.

Quiz

Function Parameters Quiz

10 quizzes