惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

A
About on SuperTechFans
Cloudbric
Cloudbric
C
CERT Recently Published Vulnerability Notes
G
GRAHAM CLULEY
V
Vulnerabilities – Threatpost
C
Cisco Blogs
T
Tenable Blog
P
Privacy International News Feed
T
The Exploit Database - CXSecurity.com
I
Intezer
AWS News Blog
AWS News Blog
IT之家
IT之家
博客园 - 司徒正美
C
Cybersecurity and Infrastructure Security Agency CISA
博客园 - 【当耐特】
The Hacker News
The Hacker News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Spread Privacy
Spread Privacy
S
SegmentFault 最新的问题
博客园 - Franky
人人都是产品经理
人人都是产品经理
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
V
Visual Studio Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
H
Hacker News: Front Page
Latest news
Latest news
Scott Helme
Scott Helme
腾讯CDC
宝玉的分享
宝玉的分享
大猫的无限游戏
大猫的无限游戏
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
A
Arctic Wolf
S
Securelist
雷峰网
雷峰网
The GitHub Blog
The GitHub Blog
Project Zero
Project Zero
Google DeepMind News
Google DeepMind News
P
Palo Alto Networks Blog
F
Fortinet All Blogs
Schneier on Security
Schneier on Security
云风的 BLOG
云风的 BLOG
Security Archives - TechRepublic
Security Archives - TechRepublic
The Last Watchdog
The Last Watchdog
WordPress大学
WordPress大学
MongoDB | Blog
MongoDB | Blog
L
LINUX DO - 最新话题
S
Schneier on Security
NISL@THU
NISL@THU
Jina AI
Jina AI
M
MIT News - Artificial intelligence

DigitalOcean Community Tutorials

Mastering grep with Regular Expressions for Efficient Text Search It's Time to Break Up with Your Cloud: Why AI Teams are Switching We Built a Private-Document AI App to Test Platform Security. Here Is What We Could Actually Verify. PostgreSQL Explained: A Complete Beginner-to-Advanced Guide How To Install and Configure Postfix on Ubuntu How To Build a Web Application Using Flask in Python 3 Build AI Reading List with DigitalOcean Functions and Mistral How To Concatenate Strings in Python How to Allow MySQL Remote Access Securely How To Install and Use Docker on Rocky Linux How To Build a Multi-Agent AI System with Docker Agent DSPy Use Cases: Build Optimized LLM Pipelines How To Submit AJAX Forms with jQuery Build an AI-Powered GPU Fleet Optimizer with the DigitalOcean AI Platform ADK Monitor GPU Utilization in Real Time: A Complete Guide Reduce File Size of Images in Linux - CLI and GUI methods Reduce PDF File Size in Linux: Tools and Methods How To Set Up a Private Docker Registry on Ubuntu How To Troubleshoot Terraform: Errors and Fixes How to Use Go Modules Python Multiprocessing Example: Process, Pool & Queue Convert Class Components to Functional Components with React Hooks How To Install and Configure Ansible on Ubuntu LLM Tokenizers Simplified: BPE, SentencePiece, and More How To Monitor System Authentication Logs on Ubuntu How to Use Traceroute and MTR to Diagnose Network Issues How to Deploy Postgres to Kubernetes Cluster Importing Packages in Go: A Complete Guide Create RAID Arrays with mdadm on Ubuntu How To Make an HTTP Server in Go How To Set Up Time Synchronization on Ubuntu How To Use Struct Tags in Go apt-key Deprecation: Add Repositories with GPG on Ubuntu Linux ps Command: 20 Real-World Examples Python struct.pack and struct.unpack for Binary Data Deadlock in Java: Examples, Detection, and Prevention How To Use Find and Locate to Search for Files on Linux Structured Resume Skill Extraction Using Mistral-7B Inference How to Use the Python Main Function How to Set Up NemoClaw on a DigitalOcean Droplet with 1-Click Build an End-to-End RAG Pipeline for LLM Applications From Single to Multi-Agent Systems: Key Infrastructure Needs Back Up Data to Object Storage Using Restic How to Generate Videos with LTX-2.3 on DigitalOcean GPU Droplets How To Install LAMP Stack (Apache, MySQL, PHP) on Ubuntu How to Download Files with cURL How To Use Variadic Functions in Go Generate UUIDs with uuidgen on Linux How To Use EJS to Template Your Node Application How to Install Node.js on Ubuntu (Step-by-Step Guide) MongoDB Indexes: Improve Query Performance with Node.js LLM Tool Calling with DigitalOcean AI Platform and Databases What are Text Diffusion Models? - An Overview Crafting a Game from Scratch with GPT-5.4 Building Long-Term Memory in AI Agents with LangGraph and Mem0 How To Install PHP 7.4 and Set Up a Local Development Environment on Ubuntu 20.04 Build a GraphQL API in Go to Upload Files to Spaces How To Lint and Format Code with ESLint in Visual Studio Code Train YOLO26 for Retail Object Detection on DigitalOcean GPUs How To Work with JSON in MySQL How to Use the JavaScript .map() Method Building a Scalable App with MongoDB Using DigitalOcean's MCP Server How to Create an SSH Key in Linux: Easy Step-by-Step Guide Measure MySQL Query Performance with mysqlslap Nemotron 3 helped me find the perfect dish rack? A2A vs MCP - How These AI Agent Protocols Actually Differ How To Install and Manage Supervisor Docker Container Images with Watchtower on Ubuntu Getting Started with Qwen3.5 Vision-Language Models How To Create a New Sudo-Enabled User on Ubuntu How to Use Ansible to Install and Set Up Docker on Ubuntu How To Enable Remote Desktop Protocol Using xrdp on Ubuntu 22.04 How To Convert a String to a List in Python How To Check If a String Contains Another String in Python How to Read a Properties File in Python Python Command Line Arguments: sys.argv, argparse, getopt Mastering Grep command in Linux/Unix: A Beginner's Tutorial Understanding Python Data Types How to Implement a Stack in C With Code Examples Python os.system() vs subprocess: Run System Commands How To Install and Use Docker Compose on Ubuntu How to Add and Delete Users on Ubuntu How To Order Query Results in Laravel Eloquent How To Define and Use Handlers in Ansible Playbooks How To Install and Use SQLite on Ubuntu How To Install and Use Homebrew on macOS How To Manage DateTime with Carbon in Laravel and PHP How To Install Git on Ubuntu How To Install and Secure Redis on Ubuntu How To Build and Install Go Programs on Linux Using ldflags to Set Version Information for Go Applications How To Build a Node.js Application with Docker How To Add JavaScript to HTML How To Reset Your MySQL or MariaDB Root Password How To Add Images in Markdown How To Set Up a Production Elasticsearch Cluster with Ansible How To Set Up a Firewall Using firewalld on CentOS Understanding Systemd Units and Unit Files How To Set Up Replication in MySQL How To Use the .htaccess File
How To Use *args and **kwargs in Python 3
Lisa Tagliaferri · 2026-03-06 · via DigitalOcean Community Tutorials

Introduction

In function definitions, parameters are named entities that specify which arguments a function can accept. When you need to support a variable number of arguments without fixing the signature, Python offers two special syntaxes: *args for extra positional arguments and **kwargs for extra keyword arguments. This tutorial covers how to define and call functions with *args and **kwargs, how to combine them with standard and keyword-only parameters, and how to use them in decorators, class inheritance, and type-annotated code.

Key Takeaways

  • *args collects extra positional arguments into a tuple; **kwargs collects extra keyword arguments into a dict.
  • Legal argument order in a function signature is: standard positional parameters, then *args, then keyword-only parameters, then **kwargs. Reversing or mixing this order causes a SyntaxError.
  • The single asterisk (*) and double asterisk (**) are the operators that matter; the names args and kwargs are conventions only.
  • You can use * and ** at the call site to unpack a sequence or mapping into positional and keyword arguments when calling a function.
  • Type annotations for *args and **kwargs (e.g., *args: int, **kwargs: str) apply to each element or value, not to the tuple or dict as a whole.
  • Prefer explicit parameters when the set of arguments is fixed and small; use *args/**kwargs for flexible APIs, decorators, and forwarding, and be aware of the small overhead of tuple and dict creation in hot paths.

Prerequisites

You should have Python 3 installed and a programming environment set up on your computer or server. If you do not have one set up, refer to the installation and setup guides for a local programming environment or for a programming environment on your server for your operating system (Ubuntu, CentOS, Debian, etc.).

Info: To follow along with the example code in this tutorial, open a Python interactive shell on your local system by running the python3 command. You can copy, paste, or edit the examples by adding them after the >>> prompt.

Understanding Python Function Arguments

Python functions accept positional arguments (matched by position) and keyword arguments (matched by name). Variable-length argument lists are handled by *args and **kwargs, which collect any extra positional or keyword arguments into a single parameter. You write a function that adds two numbers. Later you need it to add three. Then four. With fixed parameters, every change breaks existing call sites. *args and **kwargs solve this by letting the function signature grow without breaking anything.

Standard Parameters vs. Variable Arguments

Standard parameters have fixed names and a fixed count. Variable arguments allow a function to accept zero or more extra positional arguments (*args) or extra keyword arguments (**kwargs) without listing each one in the signature. The following table summarizes the two variable forms.

Feature *args **kwargs
Syntax *args **kwargs
Data structure tuple dict
Argument type positional keyword
Iteration method for val in args for k, v in kwargs.items()
Keyword required at call No Yes
Type annotation target each element each value

Argument Ordering Rules

Arguments in a function definition must appear in a strict order. The table below shows the legal order; violating it raises a SyntaxError.

Position Type Example
1 Standard positional arg_1, arg_2
2 Variable positional *args
3 Keyword-only kw_1="default"
4 Variable keyword **kwargs

Warning: Placing **kwargs before *args raises a SyntaxError immediately. Python rejects the file before running a single line. For example, def f(**kwargs, *args) produces:

SyntaxError: invalid syntax

Always follow the legal ordering: standard positional, then *args, then keyword-only, then **kwargs.

Example of a valid signature combining all four:

full_example.py

def full_example(name, age, *args, role="user", **kwargs):
    # name, age: required positional params
    # *args: captures extra positional values as a tuple
    # role: keyword-only param with a default
    # **kwargs: captures extra keyword args as a dict
    print(f"name={name}, age={age}")
    print(f"extra positional args: {args}")
    print(f"role={role}")
    print(f"extra kwargs: {kwargs}")

full_example("Sam", 30, "extra1", "extra2", role="admin", team="infra", region="us-east")
  1. python3 full_example.py

Output

name=Sam, age=30 extra positional args: ('extra1', 'extra2') role=admin extra kwargs: {'team': 'infra', 'region': 'us-east'}

Using *args to Accept Variable Positional Arguments

*args lets a function accept any number of extra positional arguments. They are collected into a single tuple, which you can iterate over or index.

How *args Works Internally

At the interpreter level, the asterisk packs all remaining positional arguments into a tuple and binds it to the name args. You can confirm this at runtime:

args_type_check.py

def inspect_args(*args):
    # Show the type and contents of args at runtime
    print(type(args))   # always <class 'tuple'>
    print(args)         # the values as a tuple
    print(args[0])      # indexing works like any tuple

inspect_args(10, 20, 30)
  1. python3 args_type_check.py

Output

<class 'tuple'> (10, 20, 30) 10

Because args is a plain tuple, you can index it, slice it, pass it to len(), or forward it to another function with *args.

Info: You can name these parameters anything valid. Use *args and **kwargs for general-purpose functions. Use descriptive names like *prices or **options when the collected values have a clear domain meaning; it makes the function signature self-documenting.

*args in Practice

A function that multiplies all given numbers can be written with *args so it works for two, three, or more arguments:

lets_multiply.py

def multiply(*args):
    # args is a tuple of all passed positional arguments
    z = 1
    for num in args:
        z *= num
    print(z)

multiply(4, 5)
multiply(10, 9)
multiply(2, 3, 4)
multiply(3, 5, 10, 6)
  1. python3 lets_multiply.py

Output

20 90 24 900

Without *args, adding a third argument would require changing the function signature and every call site. With *args, the function stays flexible.

Using **kwargs to Accept Variable Keyword Arguments

**kwargs collects extra keyword arguments into a single dict. Each argument must be passed with a keyword (e.g., name="Sam").

How **kwargs Works Internally

The double asterisk in **kwargs tells Python to pack all extra keyword arguments into a dict and bind it to the name kwargs. Keys are the parameter names used at the call site; values are the corresponding values. You can confirm this at runtime:

kwargs_type_check.py

def inspect_kwargs(**kwargs):
    # Show the type and contents of kwargs at runtime
    print(type(kwargs))          # always <class 'dict'>
    print(kwargs)                # the full dict
    print(kwargs["role"])        # direct key access like any dict
    print(kwargs.get("team", "unset"))  # safe access with a default

inspect_kwargs(role="admin", name="Sam")
  1. python3 kwargs_type_check.py

Output

<class 'dict'> {'role': 'admin', 'name': 'Sam'} admin unset

Because kwargs is a plain dict, you can use .keys(), .values(), .items(), .get(), or any other dict method on it.

**kwargs in Practice

A simple way to inspect what was passed is to print kwargs:

print_kwargs.py

def print_kwargs(**kwargs):
    # kwargs is a dict of all passed keyword arguments
    print(kwargs)

print_kwargs(kwargs_1="Shark", kwargs_2=4.5, kwargs_3=True)
  1. python3 print_kwargs.py

Output

{'kwargs_1': 'Shark', 'kwargs_2': 4.5, 'kwargs_3': True}

Note: In Python 3.7 and later, **kwargs preserves insertion order because dict is ordered by default. CPython 3.6 also maintains insertion order as an implementation detail, but earlier Python 3 versions do not guarantee iteration order.

You can iterate over key-value pairs like any other dictionary:

print_values.py

def print_values(**kwargs):
    for key, value in kwargs.items():
        # Iterate over each keyword argument and print its name and value
        print(f"The value of {key} is {value}")

print_values(my_name="Sammy", your_name="Casey")
  1. python3 print_values.py

Output

The value of my_name is Sammy The value of your_name is Casey

You can also access a specific key from kwargs with .get() and a default:

kwargs_access.py

def greet_user(**kwargs):
    # Access a specific key safely with .get(); supply a default if missing
    name = kwargs.get("name", "stranger")
    role = kwargs.get("role", "user")
    print(f"Hello, {name}. Your role is {role}.")

greet_user(name="Sam", role="admin")
greet_user(name="Alex")
  1. python3 kwargs_access.py

Output

Hello, Sam. Your role is admin. Hello, Alex. Your role is user.

Using .get() with a default prevents a KeyError when a caller omits an optional keyword argument.

Combining *args and **kwargs in One Function

A common real-world case is a log formatter that requires a severity level but accepts any number of message parts and optional metadata fields:

log_message.py

def log_message(severity, *args, **kwargs):
    # severity: required; controls log level
    # args: any number of message parts, joined into one string
    # kwargs: optional metadata fields such as user, request_id, or service
    message = " ".join(str(a) for a in args)
    metadata = ", ".join(f"{k}={v}" for k, v in kwargs.items())
    print(f"[{severity.upper()}] {message} | {metadata}" if metadata else
          f"[{severity.upper()}] {message}")

log_message("info", "User logged in")
log_message("error", "Payment failed", "retry 3 of 3", user="sam", request_id="abc123")
  1. python3 log_message.py

Output

[INFO] User logged in [ERROR] Payment failed retry 3 of 3 | user=sam, request_id=abc123

Calling log_message with only severity and no extras is valid; args will be an empty tuple and kwargs will be an empty dict.

Using *args and **kwargs When Calling Functions

The same * and ** symbols are used at the call site to unpack sequences and mappings into positional and keyword arguments. This is the inverse of collecting: you spread one sequence or dict into multiple arguments.

Unpacking a List with *

Prefixing an iterable with * unpacks its elements as positional arguments. Useful when you have a list or tuple and want to pass each element as a separate argument:

unpack_call.py

def greet(first, last, city):
    print(f"Hello, {first} {last} from {city}.")

# Unpack list for first two args, then use a dict for the third
parts = ["Ada", "Lovelace"]
location = {"city": "London"}
greet(*parts, **location)
  1. python3 unpack_call.py

Output

Hello, Ada Lovelace from London.

Here *parts supplies first and last, and **location supplies city. You can mix literal arguments with unpacking:

some_args.py

def some_args(arg_1, arg_2, arg_3):
    print("arg_1:", arg_1)
    print("arg_2:", arg_2)
    print("arg_3:", arg_3)

args = ("Sammy", "Casey", "Alex")
some_args(*args)
  1. python3 some_args.py

Output

arg_1: Sammy arg_2: Casey arg_3: Alex

Unpacking a Dictionary with **

Prefixing a mapping with ** unpacks its key-value pairs as keyword arguments. The keys must match the function’s parameter names (or be accepted by **kwargs):

some_kwargs.py

def some_kwargs(kwarg_1, kwarg_2, kwarg_3):
    print("kwarg_1:", kwarg_1)
    print("kwarg_2:", kwarg_2)
    print("kwarg_3:", kwarg_3)

kwargs = {"kwarg_1": "Val", "kwarg_2": "Harper", "kwarg_3": "Remy"}
some_kwargs(**kwargs)
  1. python3 some_kwargs.py

Output

kwarg_1: Val kwarg_2: Harper kwarg_3: Remy

Common Unpacking Errors

Two errors appear frequently when unpacking.

Error 1: Too many positional arguments:

unpack_error_positional.py

def add(a, b):
    return a + b

values = [1, 2, 3]  # one element too many
add(*values)
  1. python3 unpack_error_positional.py

Output

TypeError: add() takes 2 positional arguments but 3 were given

Unpacking a sequence with more elements than the function has parameters raises a TypeError. Count your elements or use a slice: add(*values[:2]).

Error 2: Dict key does not match parameter name:

unpack_error_keyword.py

def greet(name, city):
    print(f"Hello, {name} from {city}.")

data = {"name": "Sam", "country": "India"}  # 'country' is not a parameter
greet(**data)
  1. python3 unpack_error_keyword.py

Output

TypeError: greet() got an unexpected keyword argument 'country'

Unpacking a dict whose keys do not match the function’s parameter names raises a TypeError. Either align the dict keys to the parameter names, or ensure the function accepts **kwargs to absorb the extras.

Practical Use Cases

A decorator written without *args and **kwargs only works for functions with an exact parameter count. Apply it to any other function and it breaks. The three patterns below show how *args and **kwargs solve this in the most common real-world scenarios.

Decorator Pattern

A decorator often wraps a function without knowing its signature. Using *args and **kwargs in the wrapper lets it forward any arguments to the wrapped function. Example: a simple call logger:

decorator_example.py

import functools

def log_call(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        # Log the function name and all arguments before calling
        print(f"Calling {func.__name__} with args={args}, kwargs={kwargs}")
        result = func(*args, **kwargs)
        print(f"{func.__name__} returned {result}")
        return result
    return wrapper

@log_call
def add(x, y):
    return x + y

add(3, 7)
  1. python3 decorator_example.py

Output

Calling add with args=(3, 7), kwargs={} add returned 10 10

The wrapper accepts any positional and keyword arguments, passes them through to func, and returns the result. The same pattern appears in timing, retry, and validation decorators.

Class Inheritance with super()

When a subclass overrides __init__ and must call the parent initializer, it often forwards the same arguments. Using *args and **kwargs avoids repeating the parent’s parameter list:

inheritance_example.py

class Animal:
    def __init__(self, name, sound):
        self.name = name
        self.sound = sound

class Dog(Animal):
    def __init__(self, *args, breed="unknown", **kwargs):
        # Forward all positional and keyword args to the parent class
        super().__init__(*args, **kwargs)
        self.breed = breed

    def describe(self):
        print(f"{self.name} ({self.breed}) says {self.sound}")

d = Dog("Rex", "woof", breed="Labrador")
d.describe()
  1. python3 inheritance_example.py

Output

Rex (Labrador) says woof

Here Dog adds a breed keyword-only parameter and forwards everything else to Animal.__init__. This pattern is common in frameworks and large class hierarchies.

Framework-Style Flexible APIs

In frameworks like Flask, a decorator registers a route and passes request data to your view function. The framework’s internal machinery uses *args and **kwargs to forward URL parameters, query strings, and other context without knowing your function’s signature in advance. Here is a minimal illustration of that pattern:

flask_style.py

def route(path):
    """Simulate a framework decorator that registers a URL route."""
    def decorator(func):
        # The wrapper uses *args and **kwargs so it can forward any arguments
        # the framework collects from the request to the view function
        def wrapper(*args, **kwargs):
            print(f"Routing {path!r} -> {func.__name__}")
            return func(*args, **kwargs)
        return wrapper
    return decorator

@route("/users/<username>")
def user_profile(username):
    return f"Profile page for {username}"

# Simulate the framework calling the view with a captured URL segment
print(user_profile("sam"))
  1. python3 flask_style.py

Output

Routing '/users/<username>' -> user_profile Profile page for sam

Real Flask routes work the same way: the framework unpacks URL variables and passes them as keyword arguments to your view function, which is why view functions only declare the parameters they need.

Type Annotations with *args and **kwargs

As of Python 3.5, you can annotate the types of values collected by *args and **kwargs. The annotation describes each element or value, not the tuple or dict itself:

type_annotations_example.py

def process(*args: int, **kwargs: str) -> None:
    # Each element in args is expected to be an int
    total = sum(args)
    # Each value in kwargs is expected to be a str
    labels = ", ".join(kwargs.values())
    print(f"Sum: {total}, Labels: {labels}")

process(1, 2, 3, unit="kg", source="sensor")
  1. python3 type_annotations_example.py

Output

Sum: 6, Labels: kg, sensor

So *args: int means “each positional argument should be an int,” and **kwargs: str means “each keyword argument value should be a str.” Type checkers use these for static analysis; the interpreter does not enforce them at runtime.

To catch mismatches statically, run a type checker such as mypy:

  1. pip3 install mypy
  2. mypy type_annotations_example.py

If you call process("a", "b") instead of process(1, 2), mypy reports an Argument of type "str" is not assignable to parameter of type "int" error before the code runs. The interpreter will still execute it without raising an exception.

Performance Considerations

Using *args and **kwargs has a small runtime cost: Python builds a new tuple for the extra positional arguments and a new dict for the extra keyword arguments on each call. You can measure it with timeit:

perf_check.py

import timeit

def explicit(a, b, c):
    # Fixed parameters: no tuple or dict created
    return a + b + c

def with_args(*args):
    # *args: Python builds a tuple on every call
    return sum(args)

explicit_time = timeit.timeit(lambda: explicit(1, 2, 3), number=1_000_000)
args_time = timeit.timeit(lambda: with_args(1, 2, 3), number=1_000_000)

print(f"explicit:  {explicit_time:.3f}s")
print(f"with_args: {args_time:.3f}s")
  1. python3 perf_check.py

Output

explicit: 0.048s with_args: 0.071s

Over one million calls, *args adds roughly 20-50% overhead versus explicit parameters in a minimal function. For most application code this is irrelevant. For inner loops processing millions of items, prefer explicit parameters.

Info: Run perf_check.py on your own system to get accurate timings for your hardware and Python version. The relative difference matters more than the absolute values.

Alternative Patterns

When you need flexibility, you have several options. The table below compares them.

Approach When to use
*args / **kwargs Variable argument count, decorators, forwarding to another callable, framework-style APIs.
Pass a list or dict directly Fixed structure known to the caller; you want one object (e.g., config: dict) instead of many keyword arguments.
Dataclasses or a single object Many related fields with clear names and types; you want validation, defaults, and a single “options” object.
TypedDict Keyword-like structure with type checking; good when the set of keys is known and you want static typing for the dict.

Choose explicit parameters when the API is stable and the number of arguments is small. Use *args/**kwargs when the API must accept or forward arbitrary arguments.

FAQ

**What is the difference between *args and kwargs in Python?

*args collects extra positional arguments into a tuple. **kwargs collects extra keyword arguments into a dict. Positional arguments are passed by position (e.g., f(1, 2)); keyword arguments are passed by name (e.g., f(a=1, b=2)).

**Do I have to name them *args and kwargs?

No. The names are conventions. The single asterisk (*) and double asterisk (**) are required; you can use *values or **options or any valid identifier.

What order must arguments appear in a Python function definition?

Standard positional parameters first, then *args, then keyword-only parameters, then **kwargs. Violating this order causes a SyntaxError.

**Can I use *args and kwargs together in the same function?

Yes. Use *args before **kwargs. The function will receive a tuple of extra positional arguments and a dict of extra keyword arguments.

How do I unpack a list or dictionary when calling a function?

Use * to unpack a sequence into positional arguments (e.g., f(*my_list)). Use ** to unpack a mapping into keyword arguments (e.g., f(**my_dict)). You can combine both in one call.

**Can I type-annotate *args and kwargs?

Yes. In Python 3.5 and later you can write *args: int and **kwargs: str. The annotation applies to each element or value, not to the tuple or dict. Type checkers use these for static analysis.

**Are there performance costs to using *args and kwargs?

Yes, but usually small. Each call creates a new tuple for *args and a new dict for **kwargs. In hot paths or very high call volume, prefer explicit parameters if the argument set is fixed.

**How are *args and kwargs used in class inheritance?

Subclasses often use *args and **kwargs in __init__ (or other methods) and pass them to super().__init__(*args, **kwargs) so the parent can receive the same arguments without the subclass declaring every parent parameter. The subclass can add its own parameters before or after the forwarding.

Conclusion

*args and **kwargs let you define functions that accept a variable number of positional and keyword arguments and let you unpack sequences and mappings when calling functions. Use them when you need flexible signatures, decorators, or forwarding (e.g., to super() or framework APIs). Keep argument order correct, and prefer explicit parameters when the API is fixed and performance matters. For more on building functions, see how to define functions in Python 3 and how to use variables in Python 3.

Creative CommonsThis work is licensed under a Creative Commons Attribution-NonCommercial- ShareAlike 4.0 International License.