*args and **kwargs in Python are special function features that allow a function to accept a variable number of arguments. They are powerful because they make function interfaces more flexible, especially when the number of incoming values is not fixed ahead of time or when the function should forward arguments to another function.
At first, these names may look unusual, but the idea behind them is practical. Some functions must accept many positional values, some must accept many named options, and some must support both. Python solves that through the starred argument forms *args and **kwargs.
To use them well, you need to understand what the single star and double star actually mean, how Python packs incoming values, how these features relate to ordinary parameters, and when they make code better versus when they simply make function signatures vague.
What Are *args and **kwargs in Python?
*args collects extra positional arguments into a tuple. **kwargs collects extra keyword arguments into a dictionary. They let a function receive more values than the explicitly named parameters cover.
def demo(*args, **kwargs):
print(args)
print(kwargs)
demo(1, 2, 3, name="Ava", role="editor")
In this example, the positional values are packed into one tuple and the named values are packed into one dictionary. This is the central behavior to remember.
What *args Means
The *args form is used when a function should accept any number of extra positional arguments. Python gathers them into a tuple so the function can process them like a grouped sequence.
def show_numbers(*args):
print(args)
show_numbers(10, 20, 30)
Here, args becomes a tuple containing the values 10, 20, and 30. The name args is conventional, but not mandatory. The star behavior is what matters.
What **kwargs Means
The **kwargs form is used when a function should accept any number of extra keyword arguments. Python gathers them into a dictionary where the keys are the argument names and the values are the passed values.
def show_info(**kwargs):
print(kwargs)
show_info(name="Ava", age=21, active=True)
In this case, kwargs becomes a dictionary containing the passed name-value pairs. Again, the exact variable name is conventional rather than mandatory.
Why *args and **kwargs Are Useful
These features are useful because not every function knows in advance how many inputs it may receive. A summation helper may take any number of numbers. A wrapper function may forward settings without listing them all. A utility may accept optional configuration values that vary between calls.
This flexibility is especially valuable in reusable libraries, helper functions, decorators, wrappers, and extensible APIs. It allows the function interface to adapt without forcing every caller into one rigid argument count.
Using *args in Practice
A common use of *args is receiving several values that should be processed together. The function can loop over them, sum them, validate them, or pass them into another operation.
def total(*args):
result = 0
for value in args:
result += value
return result
print(total(1, 2, 3, 4))
This pattern is clean because the caller can provide as many values as needed without first packaging them into a fixed signature.
Using **kwargs in Practice
A common use of **kwargs is to accept optional named settings whose exact combination may vary. The function can inspect the dictionary and react to whichever options are present.
def create_user(**kwargs):
print(kwargs.get("name"))
print(kwargs.get("role"))
create_user(name="Ava", role="editor")
This is helpful in configuration-like situations, but it also requires discipline because too much hidden flexibility can make the interface harder to understand.
*args and **kwargs Together
A function may use both forms at the same time. This lets it accept extra positional values and extra keyword values in one signature.
def demo_all(*args, **kwargs):
print(args)
print(kwargs)
demo_all(1, 2, level="high", mode="test")
This is powerful, but it should be used only when the added flexibility is real and justified. Otherwise, a more explicit interface may be clearer.
Ordering Rules in Function Definitions
When several kinds of parameters appear together, Python expects a certain order in the function definition. Standard positional parameters come first, then *args if used, and **kwargs comes after that.
def example(a, b, *args, **kwargs):
print(a, b, args, kwargs)
This ordering keeps function signatures consistent and helps Python know how to match incoming values correctly.
Unpacking with * and ** at Call Time
The same star symbols also appear when calling functions. A list or tuple can be unpacked into positional arguments with *, and a dictionary can be unpacked into keyword arguments with **.
def add(a, b, c):
return a + b + c
values = [1, 2, 3]
print(add(*values))
def connect(host, port):
print(host, port)
config = {"host": "localhost", "port": 8080}
connect(**config)
This is important because it connects argument collection and argument expansion into one larger Python idea: flexible function calling through packing and unpacking.
The Names args and kwargs Are Conventions
The names args and kwargs are common conventions, not reserved keywords. A developer could technically write different names, but using the conventional names improves readability because other Python programmers immediately recognize the intent.
This is one of those cases where following convention matters. The goal is not only to make the code run. It is also to make it understandable to other people.
When *args and **kwargs Are a Good Idea
They are a good idea when flexibility is genuinely required. Examples include wrappers around other functions, helpers that accept varying numbers of values, decorators, formatting utilities, and interface layers that forward arguments onward.
They are less useful when a function really has a clear fixed contract and only hides it behind overly generic collection logic. In those cases, explicit parameters often produce better code.
Readability and API Design
A function that relies heavily on *args and **kwargs can become hard to understand if the accepted meaning of the arguments is not documented or obvious. Too much openness may shift complexity from the function definition into the caller interpretation.
That is why strong Python code treats these features as precision tools. They are excellent when the interface is genuinely variable. They are weaker when used to avoid making design decisions.
Common Mistakes with *args and **kwargs
- Thinking args and kwargs are special keywords instead of conventional names tied to star behavior.
- Using them when explicit parameters would make the function clearer.
- Forgetting that *args becomes a tuple and **kwargs becomes a dictionary.
- Confusing argument packing in the definition with argument unpacking in the function call.
- Creating interfaces so flexible that callers no longer know what the function actually expects.
Best Practices for *args and **kwargs
- Use them when the function really needs variable argument handling.
- Prefer explicit parameters when the contract is fixed and important to document clearly.
- Keep the meaning of accepted extra arguments understandable.
- Use the standard names args and kwargs for readability.
- Remember that flexibility should improve the interface, not hide it.
*args and **kwargs in Python Interview Points
For interviews, you should know that *args collects extra positional arguments into a tuple, **kwargs collects extra keyword arguments into a dictionary, the same symbols are used for unpacking at call time, and these features should be used deliberately rather than automatically.
What does *args do in Python?
*args collects extra positional arguments into a tuple inside the function.
What does **kwargs do in Python?
**kwargs collects extra keyword arguments into a dictionary inside the function.
Are args and kwargs reserved keywords in Python?
No. They are conventional names. The important part is the single star or double star behavior.
When should *args and **kwargs be used?
They should be used when a function genuinely needs variable numbers of positional or keyword inputs, such as wrappers, decorators, and flexible helpers.
*args and **kwargs Are Common in Wrapper Functions
One of the strongest use cases for variable arguments is wrapper design. A wrapper function may add logging, validation, timing, or preprocessing and then forward the original arguments to another function. In those cases, *args and **kwargs prevent the wrapper from having to repeat the full signature manually every time.
This pattern is common in decorators, adapters, and utility layers. It is one of the main reasons these features matter so much beyond beginner syntax examples.
Forwarding Arguments Cleanly
A function can receive values through *args and **kwargs and then pass them onward with the same star syntax. This keeps the argument flow flexible while preserving the original call style.
def wrapper(*args, **kwargs):
print("Before call")
return target(*args, **kwargs)
This forwarding pattern is powerful, but it also shows why documentation and clear naming still matter. Once values are collected generically, the code must still make the interface understandable.
Flexibility Should Not Replace Design
A function that accepts everything is not automatically a well-designed function. Sometimes *args and **kwargs are used to avoid deciding what the real interface should be. That usually makes the function harder to learn and easier to misuse.
Good design asks whether the variability is real. If it is, the star forms are a strong fit. If it is not, explicit parameters often produce better documentation, better tooling support, and clearer call sites.
Variable Arguments Still Need Meaning
Even when a function accepts variable arguments, the code should still make their meaning discoverable. A helper that sums numbers, a wrapper that forwards settings, or a formatter that consumes keyword options each has a real conceptual contract even if the exact count of inputs is flexible.
That is why experienced Python developers use *args and **kwargs with intention. The goal is controlled flexibility, not hidden ambiguity.
These Features Are About Reusable Interfaces
At a deeper level, *args and **kwargs are about reusable interfaces. They allow a function to stay adaptable when many callers or many calling styles must be supported. This is especially useful in frameworks, utilities, and abstraction layers where the function is acting as a bridge between different parts of the program.
Used carefully, they make APIs more extensible. Used carelessly, they can make them vague. That tradeoff is the real lesson behind the syntax.
Continue learning Python in order
Follow the topic sequence with the previous and next lesson.