Skip to content
Feb 26

Python Function Parameters

MT
Mindli Team

AI-Generated Content

Python Function Parameters

Writing clean, robust, and flexible functions is a cornerstone of effective data science. Whether you’re cleaning a dataset, training a model, or building a pipeline, mastering how information flows into your functions through parameters is what separates fragile scripts from maintainable, production-ready code.

The Foundation: Positional and Keyword Arguments

At their core, Python functions accept information through positional arguments and keyword arguments. Understanding the distinction is fundamental.

A positional argument is an argument whose value is assigned to a parameter based on its order in the function call. The first argument you pass corresponds to the first parameter, the second to the second, and so on.

def calculate_bmi(weight, height):
    return weight / (height ** 2)

# '70' is assigned to 'weight', '1.75' to 'height' based on position
result = calculate_bmi(70, 1.75)

A keyword argument (or named argument) is explicitly linked to a parameter by its name in the call, using the syntax parameter=value. This allows you to pass arguments out of order and greatly enhances code readability.

# Using keyword arguments clarifies meaning
result = calculate_bmi(height=1.75, weight=70)

The key rule is: Positional arguments must come before keyword arguments in a function call. Calling calculate_bmi(weight=70, 1.75) will raise a SyntaxError.

Adding Flexibility with Default Parameter Values

Default parameter values allow you to define a function where some parameters are optional. If the caller does not provide a value for that parameter, the default is used. This is invaluable for providing sensible defaults while allowing customization, a common pattern in data science libraries.

def load_dataset(path, delimiter=',', header=True):
    # Logic to load data using provided or default parameters
    print(f"Loading {path} with delimiter '{delimiter}' and header={header}")

load_dataset("data.csv")  # Uses default delimiter and header
load_dataset("data.tsv", delimiter='\t', header=False)  # Overrides defaults

A critical and infamous pitfall is using a mutable object, like a list or dictionary, as a default value. The default is evaluated only once when the function is defined, not each time it's called, leading to unexpected behavior where multiple calls modify the same shared object. The safe pattern is to use None as the default and create the mutable object inside the function.

# DANGEROUS: All calls share the same list
def bad_append(item, my_list=[]):
    my_list.append(item)
    return my_list

# SAFE: A new list is created for each call that uses the default
def good_append(item, my_list=None):
    if my_list is None:
        my_list = []
    my_list.append(item)
    return my_list

Handling Arbitrary Input with args and *kwargs

For maximum flexibility, Python provides mechanisms to accept an arbitrary number of arguments. This is essential for creating wrapper functions, decorators, or data aggregators.

The *args parameter (pronounced "star-args") allows a function to accept any number of positional arguments. Inside the function, args is a tuple containing all the extra positional arguments passed. The single asterisk (*) is the unpacking operator.

def calculate_sum(*args):
    total = 0
    for number in args:  # 'args' is a tuple
        total += number
    return total

print(calculate_sum(1, 5, 10, 3))  # Output: 19
# 'args' inside the function becomes (1, 5, 10, 3)

Similarly, **kwargs allows a function to accept any number of keyword arguments. Inside the function, kwargs is a dictionary mapping the keyword names to their values. The double asterisk (**) is the dictionary unpacking operator.

def generate_model_report(model_name, **kwargs):
    print(f"Report for {model_name}")
    for param, value in kwargs.items():  # 'kwargs' is a dict
        print(f"  {param}: {value}")

generate_model_report("RandomForest", n_estimators=100, max_depth=10, bootstrap=True)
# 'kwargs' becomes {'n_estimators': 100, 'max_depth': 10, 'bootstrap': True}

The Complete Parameter Ordering Rule

When defining a function, parameters must be declared in a specific, unbreakable order. This rule ensures the interpreter can correctly match arguments to parameters.

  1. Standard positional parameters
  2. *args parameter (collects extra positional args)
  3. Keyword-only parameters (parameters that must be passed by keyword)
  4. **kwargs parameter (collects extra keyword args)

Default parameters can exist for positional or keyword-only parameters. A common and powerful pattern is to use * as a placeholder to enforce keyword-only arguments after it.

# Correct order: positional, *args, keyword-only with defaults, **kwargs
def comprehensive_function(a, b, *args, flag=True, **kwargs):
    print(f"a={a}, b={b}, args={args}, flag={flag}, kwargs={kwargs}")

# Enforcing keyword-only arguments after the '*'
def create_plot(data, *, title="Chart", xlabel=None, ylabel=None):
    # 'title', 'xlabel', 'ylabel' MUST be passed as keyword arguments
    pass

create_plot([1,2,3], title="My Plot")  # Correct
# create_plot([1,2,3], "My Plot")     # TypeError

Unpacking Sequences and Dictionaries as Arguments

The same * and ** operators used in parameter definitions can be used in reverse during a function call to unpack sequences and dictionaries into arguments. This is incredibly useful when your data is already stored in a list, tuple, or dictionary.

def plot_coordinates(x, y, z):
    print(f"Plotting point at ({x}, {y}, {z})")

point_tuple = (5, 2, -1)
plot_coordinates(*point_tuple)  # Unpacks tuple: same as plot_coordinates(5, 2, -1)

config = {'learning_rate': 0.01, 'epochs': 50, 'batch_size': 32}
def train_model(learning_rate, epochs, batch_size):
    print(f"Training with LR={learning_rate}, Epochs={epochs}")

train_model(**config)  # Unpacks dict: same as train_model(learning_rate=0.01, epochs=50, batch_size=32)

This technique is ubiquitous in data science for passing configuration dictionaries or columns of a DataFrame as arguments.

Common Pitfalls

  1. Modifying Mutable Default Arguments: As covered, using my_list=[] or my_dict={} as a default leads to shared state across all function calls. Always use None as a sentinel value.
  2. Incorrect Parameter Order in Definition: Placing **kwargs before *args or mixing up the order of required and default parameters is a SyntaxError. Remember the definitive order: required positional, *args, keyword-only/default, **kwargs.
  3. Mixing Argument Types Incorrectly in a Call: In a function call, you cannot pass a positional argument after a keyword argument. my_func(a=1, 2) will always fail. Follow the call order: positional arguments first, then keyword arguments.
  4. Overusing *args and kwargs Unnecessarily:** While powerful, they can make a function's signature opaque and hide its intended use. Use them when you genuinely need flexibility (e.g., for wrappers or decorators). For most functions, explicit parameters are clearer and more maintainable.

Summary

  • Positional and Keyword Arguments form the basis of function calls. Positional arguments are matched by order; keyword arguments are matched by name and enhance clarity.
  • Default Parameter Values make arguments optional, but you must avoid mutable defaults (like [] or {}) by using None instead.
  • *args collects an arbitrary number of extra positional arguments into a tuple, while **kwargs collects extra keyword arguments into a dictionary. They are essential for creating highly flexible and reusable functions.
  • Parameter Definition Order is Strict: Remember the sequence: standard positional, *args, keyword-only/default, **kwargs. You can use a bare * to enforce keyword-only arguments.
  • Argument Unpacking uses * to unpack a sequence into positional arguments and ** to unpack a dictionary into keyword arguments, allowing you to call functions with pre-collected data structures seamlessly.

Write better notes with AI

Mindli helps you capture, organize, and master any subject with AI-powered summaries and flashcards.