Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions python-optional-arguments/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Using Python Optional Arguments When Defining Functions

This folder contains accompanying code to the Real Python tutorial on [Using Python Optional Arguments When Defining Functions](https://realpython.com/python-optional-arguments/).

You can read each file and its comments, and run the files to see the code's output.
32 changes: 32 additions & 0 deletions python-optional-arguments/mutable_default_bug.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""
Demonstrates why using a mutable default (like {}) is a bad idea.

This mirrors the tutorial's buggy example so you can reproduce the issue.
Run this file directly to see both variables share the same underlying dict.
"""


def add_item(item_name, quantity, shopping_list={}):
# BAD: the default dict is created once and reused
if item_name in shopping_list:
shopping_list[item_name] += quantity
else:
shopping_list[item_name] = quantity
return shopping_list


clothes_shop_list = add_item("Shirt", 3) # Uses the shared default dict
electronics_store_list = add_item("USB cable", 1) # Same shared dict!

print("clothes_shop_list:")
for k, v in clothes_shop_list.items():
print(f"{v}x {k}")

print("\nelectronics_store_list:")
for k, v in electronics_store_list.items():
print(f"{v}x {k}")

print(
"\nNote how both lists contain the same combined items "
"due to the shared default."
)
86 changes: 86 additions & 0 deletions python-optional-arguments/optional_params.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"""
Optional arguments in Python — consolidated, runnable examples.

This module collects the tutorial's final, good-practice implementations:

- show_list(shopping_list, include_quantities=True)
- add_item(item_name, quantity, shopping_list=None)
- add_items_args(shopping_list, *item_names)
- add_items_kwargs(shopping_list, **things_to_buy)

Run the module directly to see a short demo.
"""


def show_list(shopping_list, include_quantities=True):
for item_name, quantity in shopping_list.items():
if include_quantities:
print(f"{quantity}x {item_name}")
else:
print(item_name)
print()


def add_item(item_name, quantity, shopping_list=None):
"""Add (or increment) an item in a list using the safe 'None' default."""
if shopping_list is None:
shopping_list = {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔧 Technical Recommendation

The name shopping_list may imply Python's list data structure, while we actually use the variable to store a Python dictionary. How about renaming this variable to shopping_items or item_quantities instead?

if item_name in shopping_list:
shopping_list[item_name] += quantity
else:
shopping_list[item_name] = quantity
return shopping_list


def add_items_args(shopping_list, *item_names):
"""Add any number of item names with default quantity 1 using *args."""
for item_name in item_names:
if item_name in shopping_list:
shopping_list[item_name] += 1
else:
shopping_list[item_name] = 1
return shopping_list


def add_items_kwargs(shopping_list, **things_to_buy):
"""Add any number of items with explicit quantities using **kwargs."""
for item_name, quantity in things_to_buy.items():
if item_name in shopping_list:
shopping_list[item_name] += quantity
else:
shopping_list[item_name] = quantity
return shopping_list


# --- Using required + optional parameters (safe default pattern) ---
hardware_store_list = {}
hardware_store_list = add_item("Nails", 1, hardware_store_list)
hardware_store_list = add_item("Screwdriver", 1, hardware_store_list)
hardware_store_list = add_item("Glue", 3, hardware_store_list)

supermarket_list = {}
supermarket_list = add_item("Bread", 1, supermarket_list)
supermarket_list = add_item("Milk", 2, supermarket_list)

show_list(hardware_store_list) # With quantities
show_list(supermarket_list, False) # Names only

# Create new lists on the fly by omitting shopping_list
clothes_shop_list = add_item(
"Shirt", 3
) # New dict created inside the function
electronics_store_list = add_item("USB cable", 1) # New dict created again
show_list(clothes_shop_list)
show_list(electronics_store_list)

# --- Using *args to add many items at once (defaults quantity to 1) ---
multi_add_list = {}
multi_add_list = add_items_args(
multi_add_list, "Coffee", "Tea", "Cake", "Bread"
)
show_list(multi_add_list)

# --- Using **kwargs to add items with explicit quantities ---
kw_list = {}
kw_list = add_items_kwargs(kw_list, coffee=1, tea=2, cake=1, bread=3)
show_list(kw_list)
11 changes: 11 additions & 0 deletions python-optional-arguments/unpacking_demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""
Unpacking operator demo to support the *args discussion.
"""

some_items = ["Coffee", "Tea", "Cake", "Bread"]

print("Passing the list as a single argument:")
print(some_items) # -> ['Coffee', 'Tea', 'Cake', 'Bread']

print("\nUnpacking the list with *some_items:")
print(*some_items) # -> Coffee Tea Cake Bread