19.7 inspect.signature() and Introspecting Callables

The inspect.signature() function is the cornerstone of runtime callable introspection in Python, providing a powerful, standardized way to examine the parameters a function or method expects. It returns a Signature object, which is a rich, structured representation of the callable’s signature, far surpassing the basic information provided by older methods like inspect.getargspec() (now deprecated). This object allows you to programmatically understand not just the names of parameters, but also their kinds (positional, keyword, etc.), default values, and annotations, making it indispensable for building frameworks, decorators, validation libraries, and interactive tools.

19.6 Forwarding Arguments with * and ** Unpacking

Forwarding arguments using the * and ** unpacking operators is a cornerstone of writing flexible and reusable Python functions. It allows a function to accept an arbitrary number of arguments and then pass them, without alteration, to another function. This pattern is fundamental to decorators, wrapper functions, and class inheritance, enabling a layer of abstraction to be inserted without interfering with the underlying function’s signature. The mechanism works by “unpacking” a sequence (like a list or tuple) into positional arguments and a mapping (like a dict) into keyword arguments. When used in a function call, the * operator unpacks an iterable, and the ** operator unpacks a dictionary.

19.5 Combining All Parameter Kinds: The Full Signature

The Complete Parameter Hierarchy When combining all parameter types in a single function signature, Python enforces a strict ordering that maintains consistency and prevents ambiguity. The complete hierarchy, from left to right, is: Positional-only parameters (may include regular positional parameters) *args for variable positional arguments Keyword-only parameters **kwargs for variable keyword arguments This structure ensures Python can unambiguously determine which argument corresponds to which parameter. Any deviation from this order will result in a SyntaxError.

19.4 Positional-Only Parameters (Before /, Python 3.8+)

Positional-only parameters, introduced in Python 3.8 via the / character in a function signature, represent a significant and deliberate shift in how a function’s interface can be designed. They enforce a specific calling convention, requiring that certain arguments be passed by position and never by keyword. This feature is not about enabling new functionality but about providing API designers with a tool for clarity, robustness, and backward compatibility. The primary motivation for positional-only parameters is to give library and framework authors greater control over their public APIs. Before Python 3.8, a parameter’s name was part of its public contract. If a user started passing an argument by keyword, the author could not later change that parameter’s name without breaking the user’s code. By marking parameters as positional-only, the name is effectively made private and can be changed in future versions without affecting any existing calls that use the positional convention. This is why you see heavy use of / in built-in functions like len(), print(), and range(); their authors retain the freedom to refactor.

19.3 Keyword-Only Parameters (After *)

Keyword-only parameters are a powerful feature introduced in Python 3.0 that enforces clarity and intentionality in function calls. They are defined syntactically by placing them after a single bare * in the function’s parameter list. This * acts as a syntactic separator, indicating that all subsequent parameters must be passed using their keyword. This design prevents them from being passed as positional arguments, which is a common source of errors in APIs where certain parameters are optional but carry significant meaning.

19.2 **kwargs: Variadic Keyword Arguments

The **kwargs parameter is a powerful tool that allows a function to accept an arbitrary number of keyword arguments. The name kwargs is a convention, short for “keyword arguments,” but the critical element is the double asterisk (**) prefix. This prefix instructs Python to pack any remaining keyword arguments that do not correspond to explicitly named parameters into a dictionary. The keys of this dictionary are the argument names (as strings), and the values are the corresponding argument values passed by the caller. This mechanism is essential for creating flexible and extensible APIs, data processing functions, and decorators.

19.1 *args: Variadic Positional Arguments

The *args parameter is a fundamental tool in Python for creating functions that can accept a variable number of positional arguments. The asterisk (*) prefix is the syntax that enables this behavior, colloquially known as “splat” or “unpacking” operator. When used in a function definition, it collects any number of extra positional arguments into a tuple. This mechanism is essential for writing flexible and reusable code where the exact number of inputs cannot be predetermined.

— joke —

...