Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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("\nclothes_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):
print()
for item_name, quantity in shopping_list.items():
if include_quantities:
print(f"{quantity}x {item_name}")
else:
print(item_name)


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
Copy Markdown
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