diff --git a/python-optional-arguments/README.md b/python-optional-arguments/README.md new file mode 100644 index 0000000000..80526f9df1 --- /dev/null +++ b/python-optional-arguments/README.md @@ -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. diff --git a/python-optional-arguments/mutable_default_bug.py b/python-optional-arguments/mutable_default_bug.py new file mode 100644 index 0000000000..b77273c6bc --- /dev/null +++ b/python-optional-arguments/mutable_default_bug.py @@ -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." +) diff --git a/python-optional-arguments/optional_params.py b/python-optional-arguments/optional_params.py new file mode 100644 index 0000000000..a8ee01994b --- /dev/null +++ b/python-optional-arguments/optional_params.py @@ -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 = {} + 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) diff --git a/python-optional-arguments/unpacking_demo.py b/python-optional-arguments/unpacking_demo.py new file mode 100644 index 0000000000..8e62b74140 --- /dev/null +++ b/python-optional-arguments/unpacking_demo.py @@ -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