Functions & Scope

15 questions found

How do you use functools.partial to create a new function with some arguments pre-filled?

Advanced
functools.partial(func, *args, **kwargs) returns a NEW callable that, when invoked, calls the ORIGINAL function with the pre-filled arguments PLUS whatever additional arguments are passed at call time — a clean, explicit alternative to writing a small wrapper lambda for the same purpose.
from functools import partial

def power(base, exponent):
    return base ** exponent

square = partial(power, exponent=2)  # 'exponent' pre-filled
print(square(5))  # 25, equivalent to power(5, exponent=2)
Real-world example Creating a specialized, pre-configured version of a generic function, like a square() function derived from a general power() function.

Common follow-ups: How does functools.partial differ from simply writing an equivalent lambda that calls the original function?

functools & Functional Programming Tools

How does Python evaluate default argument expressions ONLY ONCE at definition time, and what SAFE pattern exploits this for genuinely useful caching?

Advanced
Since a default value's expression is evaluated exactly once when the 'def' statement runs (not per-call), you can deliberately exploit this to CACHE an expensive computation as a function's own default argument — an unusual but valid technique for memoizing a value computed once and reused across all calls.
def expensive_computation():
    print("Computing...")
    return 42

def use_cached_value(value=expensive_computation()):  # runs ONCE, at def time
    return value

print(use_cached_value())  # 'Computing...' printed once, then 42
print(use_cached_value())  # just 42, NOT recomputed
Real-world example Deliberately caching an expensive, one-time initialization value as a function's default argument (an unusual but occasionally useful trick).

Common follow-ups: Why is this technique considered clever but potentially CONFUSING to other developers reading the code later?

functools & Functional Programming Tools

How do you correctly type-hint a function using *args and **kwargs with modern typing, like ParamSpec for preserving a wrapped function's exact signature?

Advanced
typing.ParamSpec (Python 3.10+) lets you capture an ENTIRE parameter signature (both positional and keyword parts) as a single type variable, letting a generic decorator's type hints correctly preserve the WRAPPED function's exact original signature — something plain *args: Any, **kwargs: Any annotations can't express.
from typing import ParamSpec, TypeVar, Callable

P = ParamSpec("P")
R = TypeVar("R")

def logged(func: Callable[P, R]) -> Callable[P, R]:
    def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
        print(f"Calling {func.__name__}")
        return func(*args, **kwargs)
    return wrapper
Real-world example Writing a fully type-safe generic decorator whose type checker output correctly reflects the wrapped function's exact original parameter types.

Common follow-ups: How does a type checker like mypy actually USE ParamSpec to verify calls to the wrapped, decorated function?

Type Hints

How would you implement a function that dynamically inspects its own call arguments at runtime using the 'inspect' module, useful for building generic validation or logging decorators?

Advanced
inspect.signature(func).bind(*args, **kwargs) maps the ACTUAL passed arguments to their corresponding PARAMETER NAMES (correctly handling positional, keyword, defaults, *args, and **kwargs), letting you build generic tooling (like validation or logging) that needs to reason about arguments BY NAME regardless of how the caller actually passed them.
import inspect

def log_arguments(func):
    sig = inspect.signature(func)
    def wrapper(*args, **kwargs):
        bound = sig.bind(*args, **kwargs)
        bound.apply_defaults()
        print(f"Called with: {dict(bound.arguments)}")
        return func(*args, **kwargs)
    return wrapper

@log_arguments
def greet(name, greeting="Hello"):
    return f"{greeting}, {name}!"

greet("Sam")  # logs: {'name': 'Sam', 'greeting': 'Hello'}
Real-world example Building a generic argument-logging or validation decorator that correctly maps ANY call style (positional or keyword) back to parameter names.

Common follow-ups: What does bound.apply_defaults() specifically add that raw sig.bind() alone wouldn't include?

Decorators

What does it mean that functions are 'first-class objects' in Python?

Beginner
Functions can be assigned to variables, passed as arguments to other functions, returned from functions, and stored in data structures like lists or dicts -- treated just like any other value (an int or a string) rather than being a special, restricted kind of construct.
def greet():
    return "Hello!"

say_hello = greet          # assigned to a variable
functions = [greet, print]  # stored in a list

def call_it(func):           # passed as an argument
    return func()

print(call_it(greet))  # "Hello!"
Real-world example Passing a specific comparison or transformation function as an argument to a generic sorting or processing utility.

Common follow-ups: How does this first-class function support directly enable Python's decorator syntax?

Decorators

Showing 11–15 of 15