Back to Blog
Python

Python Function Declaration: Syntax and Parameters

Learn the syntax for declaring functions in Python, including parameters, return values, default arguments, *args/**kwargs, and type hints.

python functionsfunction syntaxparameterstype hintsdefault argumentsvariable-length arguments
Illustration of Python function declaration showing def keyword and parameters.

In Python, a function declaration is the syntax that defines a callable block of code. It begins with the def keyword, followed by the function name, a parenthesized parameter list, and a colon. The function body is an indented block. Function names must follow Python's identifier rules: letters, digits, and underscores, not starting with a digit. The parameter list can be empty or contain parameters separated by commas.

def greet(): print("Hello, world!")

Calling greet() executes the body. The declaration itself does not run the body until the function is called. This distinction matters when a function has side effects or expensive setup.

Parameters and Arguments in Function Declarations

Parameters are names bound to values passed at call time. The declaration defines the expected input, and the caller supplies arguments. Arguments can be passed positionally or by keyword; positional arguments are matched to parameters by position, and keyword arguments by name.

def add(a, b): return a + b result = add(3, 5) # positional result = add(a=3, b=5) # keyword

Keyword arguments improve readability when a function has many parameters. They also allow the caller to skip optional parameters, as long as defaults are defined.

Return Values and the return Statement

A function can return a value using the return statement. If no return is executed, the function returns None. The return statement exits the function immediately, so any code after it is unreachable.

def square(x): return x * x

Returning multiple values is done by returning a tuple, which can be unpacked at the call site.

def min_max(numbers): return min(numbers), max(numbers) low, high = min_max([4, 1, 9, 3])

Default and Keyword-Only Parameters

Parameters can have default values, making them optional in the call. Defaults are evaluated once at function definition time, not at each call. This matters when the default is a mutable object like a list or dictionary.

def add_item(item, items=[]): items.append(item) return items

This declaration has a subtle bug: the default list is shared across all calls. The safer pattern is to use None and create a new list inside the body.

def add_item(item, items=None): if items is None: items = [] items.append(item) return items

Python also supports keyword-only parameters, which must be passed by name. They appear after a * in the parameter list.

def configure(host, port, *, timeout=30): ...

Here, timeout can only be provided as a keyword argument, preventing accidental positional misuse.

Variable-Length Arguments: *args and **kwargs

When a function must accept an arbitrary number of arguments, the declaration uses *args for positional arguments and **kwargs for keyword arguments. The names args and kwargs are conventional but not enforced.

def log(level, *messages): for msg in messages: print(level, msg) def render(template, **context): ...

Regardless of the names chosen, the parameter bound by * receives a tuple, and the parameter bound by ** receives a dictionary. This pattern is common in decorators, wrappers, and functions that delegate to other callables.

Type Hints and Annotations in Declarations

Type hints were introduced in Python 3.5 as a standard way to annotate parameter and return types. They do not enforce types at runtime; they serve as documentation and enable static analysis tools like mypy.

def add(a: int, b: int) -> int: return a + b

Annotations can also be used for other metadata, but type hints are the most common use. They improve maintainability by making the expected contract explicit, especially in larger codebases.

Scope, Nested Functions, and Closures

When a function is called, it creates a new local scope. Variables assigned inside the function are local unless declared global or nonlocal. Nested function declarations can capture variables from the enclosing scope, forming a closure.

def make_counter(): count = 0 def increment(): nonlocal count count += 1 return count return increment

The inner function increment refers to count from the outer scope. The nonlocal declaration is required to modify that variable. Closures are useful for creating stateful functions without classes.

Common Mistakes and Misconceptions

One frequent mistake is forgetting the colon at the end of the declaration line, which causes a SyntaxError. Another is mixing positional and keyword arguments incorrectly: positional arguments must appear before keyword arguments in a call. In the parameter list, parameters with defaults must come after parameters without defaults.

# Correct def f(a, b=1): ... # Incorrect def f(a=1, b): ...

Also, mutable default arguments are a classic pitfall, as described earlier. Understanding these details helps you write function declarations that behave predictably across calls.

Python Function Declaration: Syntax and Parameters | RYUSLOG DEV