*args and **kwargs let a function accept a variable number of arguments.
*args: extra positional arguments as a tuple.**kwargs: extra keyword arguments as a dict.- Names
args/kwargsare convention; the*/**are what matter.
Parameter order (simplified): normal params → *args → keyword-only → **kwargs.
def report(title, *args, urgent=False, **kwargs):
print("title:", title)
print("args:", args)
print("urgent:", urgent)
print("kwargs:", kwargs)
report("ETL", "orders", "payments", urgent=True, owner="de-team")
# title: ETL
# args: ('orders', 'payments')
# urgent: True
# kwargs: {'owner': 'de-team'}
# Unpacking when calling
cols = ["a", "b"]
opts = {"sep": ",", "end": "!\n"}
print(*cols, **opts) # a b!
def forward(*args, **kwargs):
return report("proxy", *args, **kwargs)Use them for wrappers, decorators, and flexible APIs. Prefer explicit parameters when the interface is stable and known.