Get Function Signature - Python
A function signature in Python defines the name of the function, its parameters, their data types , default values and the return type. It acts as a blueprint for the function, showing how it should be called and what values it requires. A good understanding of function signatures helps in writing clear, readable and efficient code.
Example:
def add(a, b):
return a + b
print(add(4,5))
Output
9
Explanation: In this example, the function add takes two parameters a and b, both of type int and returns an int.
Methods to retrieve function signature
Using inspect.signature()
inspect module offers a function called signature() that allows us to get the signature of any callable object in Python. This is a powerful tool for analyzing functions, methods, and even classes.
Syntax:
import inspect
inspect.signature(callable)
Example:
import inspect
# function with parameters
def fun(arg1: int, arg2: str, *args: int, **kwargs: float) -> bool:
pass
# retrieve the function's signature
sig = inspect.signature(fun)
print(sig)
# Access specific parameter details
for param in sig.parameters.values():
print(f"Parameter: {param.name}")
print(f"Type: {param.annotation}")
print(f"Default: {param.default}")
print(f"Kind: {param.kind}")
print("---")
Output
(arg1: int, arg2: str, *args: int, **kwargs: float) -> bool
Parameter: arg1
Type: <class 'int'>
Default: <class 'inspect._empty'>
Kind: POSITIONAL_OR_KEYWORD
---
Parameter: arg2
Type: <class 'str'>
Default: <class 'inspect._empty'>
Kind: POSITIONAL_OR_KEYWORD
---
Parameter: args
Type: <class 'int'>
Default: <class 'inspect._empty'>
Kind: VAR_POSITIONAL
---
Parameter: kwargs
Type: <class 'float'>
Default: <class 'inspect._empty'>
Kind: VAR_KEYWORD
---
Explanation: Here, inspect.signature() provides the full signature, including positional parameters (arg1, arg2), variable positional arguments (*args) and keyword arguments (**kwargs). We can also access individual parameter details such as their types and default values.
Using inspect.getfullargspec()
Another useful function from the inspect module is getfullargspec(). It provides a comprehensive breakdown of the function's arguments, including default values for each parameter, the type annotations, and information about variable positional arguments (*args) and keyword arguments (**kwargs). Example:
import inspect
def fun(arg1: int, arg2: str, *args: int, **kwargs: float) -> bool:
pass
argspec = inspect.getfullargspec(fun)
print(f"Arguments: {argspec.args}")
print(f"Default Values: {argspec.defaults}")
print(f"Annotations: {argspec.annotations}")
Output
Arguments: ['arg1', 'arg2'] Default Values: None Annotations: {'return': <class 'bool'>, 'arg1': <class 'int'>, 'arg2': <class 'str'>, 'args': <class 'int'>, 'kwargs': <class 'float'>}
Explanation: Here, argspec.args lists the positional arguments, argspec.defaults provides the default values (if any) and argspec.annotations includes the type annotations.
Using __code__Artibute
For more low-level access to function details, Python functions have a __code__ attribute, which contains bytecode information about the function. The co_varnames attribute lists the names of the function's variables and the co_argcount attribute provides the number of positional arguments. Example:
def fun(a, b, *args, **kwargs):
pass
print(fun.__code__.co_varnames)
print(fun.__code__.co_argcount)
Output
('a', 'b', 'args', 'kwargs') 2
Explanation: Here, co_varnames lists the function's variables and co_argcount indicates the number of positional arguments.
Using decorators
In addition to using the inspect module directly, decorators can be used to capture and display function signatures during runtime. This method allows you to add extra behavior, like logging function calls or debugging, without modifying the original function. Example:
def function_details(func):
def wrapper(*args, **kwargs):
# Retrieve argument names using func.__code__
argnames = func.__code__.co_varnames[:func.__code__.co_argcount]
print(f"Function: {func.__name__}()")
# Print the arguments passed to the function
print(", ".join(f"{arg}={value}" for arg, value in zip(argnames, args)), end=" ")
# Print variable arguments
if args[len(argnames):]:
print(f"args={args[len(argnames):]}", end=" ")
# Print keyword arguments
if kwargs:
print(f"kwargs={kwargs}", end=" ")
print(")")
return func(*args, **kwargs)
return wrapper
# Applying the decorator
@function_details
def example_function(a, b=1, *args, **kwargs):
pass
example_function(10, 20, 30, 40, name="John", age=25)
Output
Function: example_function() a=10, b=20 args=(30, 40) kwargs={'name': 'John', 'age': 25} )
Explanation: This decorator prints the function’s name along with the arguments passed, including positional arguments, variable arguments and keyword arguments.