Functions are defined using the def keyword, followed by the function name, parameters in parentheses, and a colon, as in def function_name(parameters):. The indented body contains the function's logic, and you call the function by writing its name followed by arguments, like function_name(args). It is important to distinguish between parameters, which are the variables listed in the function definition, and arguments, which are the actual values passed when calling the function. Keyword arguments can be passed using the name=value syntax.
The return statement, written as return value, exits the function and sends a value back to the caller. Without an explicit return, a function automatically returns None. Default parameters let you assign a default value to a parameter so the caller can omit it: def func(param=default):. This is helpful when a parameter has a common value most callers will want.
For more flexible function signatures, Python supports *args and **kwargs. The *args syntax packs extra positional arguments into a tuple, while **kwargs packs extra keyword arguments into a dictionary. These constructs allow a function to accept any number of arguments without specifying them all in advance.