Python Pizza Party: Unleash *args & kwargs for Infinite Topping Combos 🍕

Pushkar ShuklaPushkar Shukla
5 min read

Imagine You’re a Party Host…

You’ve thrown a house party. Sometimes five friends show up, sometimes twenty — but you always need a way to greet everyone. In Python, your greeting function might get overwhelmed if you hard-code four names. Instead, you’d love something like, “Hey, whoever’s here, welcome!” That’s exactly the power of *args (for unnamed guests) and **kwargs (for specialized guests with name tags).

The “Uh-Oh” Moment

You write:

def greet(a, b, c):
    print(f"Hello {a}, {b}, and {c}! Enjoy the party.")

greet("Pushkar", "Spoidermon", "Rahul")
# Works fine!

Then Thor decides to join

greet("Pushkar", "Spoidermon", "Rahul", "Thor")
# TypeError: greet() takes 3 positional arguments but 4 were given

😱 You can’t say “Thor” without rewriting the function. We need something more flexible.


Meet *args: Your Positional Party Bouncer

(Variable-Length Positional Arguments)

  • Syntax: a single asterisk * before a parameter name (by convention often args but you can call it guests, things, whatever).

  • Inside: it becomes a tuple of all extra positional arguments.

      def greet_everyone(*guests):
          for guest in guests:
              print(f"Hey {guest}, glad you’re here!")
    

    Using it:

      greet_everyone("Pushkar", "Spoidermon", "Rahul", "Thor")
      # Hey Pushkar, glad you’re here!
      # Hey Spoidermon, glad you’re here!
      # Hey Rahul, glad you’re here!
      # Hey Thor, glad you’re here!
    

    Why Tuples Rock Here

    • Immutable: You can’t accidentally shuffle guests around.

    • Lightweight: Perfect for unpacking unknown counts.

💡 Newbie Tip: Even though it’s a tuple, you can convert it to a list if you really need to reorder or pop items:

guest_list = list(guests)

Now enters **kwargs: The VIP Treatment

Variable-Length Keyword Arguments

Sometimes friends annoying but different preferences:

  • “I’m lactose intolerant.”

  • “I only eat gluten-free.”

  • “I need a charger for my phone.”

These are keyword preferences, and they vary in type and count. That’s where **kwargs shines.

  • Syntax: double asterisks ** before a parameter name (often kwargs, but could be preferences).

  • Inside: you get a dict mapping each keyword to its value.

def party_preferences(**prefs):
    print("Here’s what everyone needs:")
    for name, pref in prefs.items():
        print(f" - {name} wants {pref}")

Example:

party_preferences(
    Pushkar="vegan snacks",
    Spoidermon="extra blanket",
    Rahul="veggie pizza"
)
# Here’s what everyone needs:
#  - Pushkar wants vegan snacks
#  - Spoidermon wants extra blanket
#  - Rahul wants veggie pizza

Combining Forces: The Ultimate Party Planner

You’re planning a pizza party. You need to know the size, which toppings, and extra named options:

def plan_pizza(size, *toppings, **options):
    print(f"🎉 Rolling out a {size}-inch pizza!")
    if toppings:
        print("Toppings:")
        for t in toppings:
            print(f"  • {t}")
    if options:
        print("Special Requests:")
        for k, v in options.items():
            print(f"  – {k}: {v}")
    print("Enjoy your feast!\n")

# Let’s test it:
plan_pizza(
    12,
    "pepperoni", "mushrooms", "corn",
    extra_cheese=True,
    crust_type="thin"
)

Output:

🎉 Rolling out a 12-inch pizza!
Toppings:
  • pepperoni
  • mushrooms
  • corn
Special Requests:
  – extra_cheese: True
  – crust_type: thin
Enjoy your feast!

Anatomy of a Flexible Function:

In Python, the order of arguments in a function definition follows a specific sequence:

  1. Positional Arguments – Regular arguments that must be passed in order.

  2. Default Arguments – Arguments with default values that become optional.

  3. Variable-Length Positional Arguments (*args) – Collects extra positional arguments into a tuple.

  4. Keyword-Only Arguments – Named arguments that must be passed using keywords.

  5. Variable-Length Keyword Arguments (**kwargs) – Collects extra keyword arguments into a dictionary.

Example:

def example(a, b=2, *args, c, d=4, **kwargs):
    pass
  • a must be passed positionally.

  • b can be positional or keyword.

  • *args picks up unclaimed positional args.

  • c must be named.

  • d is an optional named argument with default.

  • **kwargs grabs anything else.

What if we have toppings in list and Options in dictionary?

Got toppings in a list and options in a dict? No problem:

#Same starting code that we wrote above
topping_list = ["ham", "pineapple", "olive"]
option_dict = {"extra_sauce": True, "cut_style": "square"}

plan_pizza(10, *topping_list, **option_dict)

Output:

🎉 Rolling out a 12-inch pizza!
Toppings:
  • pepperoni
  • mushrooms
  • corn
Special Requests:
  – extra_cheese: True
  – crust_type: thin
Enjoy your feast!

🎉 Rolling out a 10-inch pizza!
Toppings:
  • ham
  • pineapple
  • olive
Special Requests:
  – extra_sauce: True
  – cut_style: square
Enjoy your feast!

Common “Oops!” Moments

  1. Mixing positionals and keywords incorrectly
# This is invalid because you used a keyword argument (size=12)
# before a positional argument ("pepperoni").
plan_pizza(size=12, "pepperoni", crust="thin")
#            ^^^^^^^
# SyntaxError: positional argument follows keyword argument
#--------------------------------------------------------------------
# This is valid: you supply all positional args first,
# then any keyword args.
plan_pizza(12, "pepperoni", crust="thin")
# ^ positional for size
#   ^ positional for toppings
#                  ^^^^^ keyword for crust

Always pass unnamed args before keywords.

Forgetting the asterisks when calling functions

toppings = ["tomato", "cheese"]
plan_pizza(8, toppings)           # treats toppings as one tuple element
plan_pizza(8, *toppings)          # correct unpacking

Quick Quiz

Which call works for this signature?

def foo(x, *args, y, **kwargs): ...

A. foo(1, 2, 3, y=4, z=5)
B. foo(1, y=4, 2, 3)
C. foo(x=1, *[2,3], y=4)

Answer: A and C are valid. B is invalid because you can’t have positional args after a keyword.

To avoid confusion: in A option, *args will take the values (2,3)

Conclusion

*args and **kwargs transform your Python functions from rigid “only four arguments allowed” to nimble, catch-anything works wonders. Remember:

  • *args → pack extra positional args into a tuple.

  • **kwargs → pack extra keyword args into a dict.

  • Unpacking → reverse the process with * and ** when calling.

Next time you face a function that feels too strict, whip out your asterisks and let Python do the heavy lifting. Happy coding—now go plan that infinitely customizable pizza party! 🍕🎉

Check a different and very simpler explanation here on Google Collab:

Click Me 🙈

2
Subscribe to my newsletter

Read articles from Pushkar Shukla directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Pushkar Shukla
Pushkar Shukla