Skip to main content

Function Arguments

In Python, lists and dictionaries are passed by object reference, meaning changes made to them inside a function affect the original object.

Flexible Arguments (*args and **kwargs)

These allow our functions to accept any number of inputs.

  • *args collects extra positional arguments into a tuple, while
  • **kwargs collects keyword arguments into a dictionary.
def build_profile(name, *skills, **details):
print(f"Name: {name}")
print(f"Skills (tuple): {skills}")
print(f"Details (dict): {details}")
for key, value in details.items():
print(f"Extra Detail: {key}: {value}")

build_profile("Aman", "Python", "C", location="India", role="Dev")

Output:

Name: Aman
Skills (tuple): ('Python', 'C')
Details (dict): {'location': 'India', 'role': 'Dev'}
Extra Detail: location: India
Extra Detail: role: Dev
Order Matters

The standard order for arguments is: positional, *args, keyword, and then **kwargs.

The Mutable Default Trap

Never use mutable objects like lists or dictionaries as default arguments.
In Python, these are created once when the function is defined, not every time it is called, meaning the same object is shared across all calls.

# Anti-pattern: The same list is shared across all calls!
def add_item(item, basket=[]):
basket.append(item)
return basket

print(add_item("Apple"))
print(add_item("Banana")) # Oops! Shared list
['Apple']
['Apple', 'Banana']

The Pythonic Fix

Use None as a placeholder and initialize the list inside the function logic.

def add_item_safe(item, basket=None):
if basket is None:
basket = []
basket.append(item)
return basket

print(add_item_safe("Apple"))
print(add_item_safe("Banana")) # New list each time
['Apple']
['Banana']