Skip to main content

1. Defining and Calling Functions

A function is a named block of code that performs a specific task. You define it once, then call it whenever you need that task done.

Function Syntax

Every function follows this pattern:
Key parts:
  • def: keyword that creates a function.
  • Function name followed by parentheses ().
  • Colon : to start the function body.
  • Indented code block (the function body).

Naming Functions

Follow these rules for function names (Snake Case):
  • Use lowercase letters.
  • Separate words with underscores.
  • Be descriptive about what the function does.

2. Parameters & Arguments

Parameters let you pass data into functions. Instead of hardcoding values, you make functions flexible to work with different inputs.
[!NOTE] The variables in the function definition are parameters. The actual values you pass when calling the function are arguments.

Positional Arguments

By default, Python matches the arguments you pass to the parameters in the definition by their position (order).

Default Values

You can give parameters default values to make them optional:
[!TIP] Always put parameters with default values at the end of the parameter list.

Keyword Arguments

You can call functions using parameter names for clarity, which allows you to pass them in any order:

3. Return Values

Use the return statement to send a value back from a function to the caller.
[!IMPORTANT] When Python encounters a return statement, it immediately exits the function. Any code after the return statement will not execute.

Returning Multiple Values

You can return multiple values from a function by separating them with commas. Python wraps them in a tuple automatically:

4. Flexible & Enforced Arguments

Python provides advanced options for handling dynamic numbers of arguments and enforcing calling styles.

Variable-Length Arguments (*args)

Prefix a parameter name with a single asterisk * to accept any number of positional arguments. Inside the function, args is a tuple.

Variable Keyword Arguments (**kwargs)

Prefix a parameter name with a double asterisk ** to accept any number of keyword arguments. Inside the function, kwargs is a dictionary.

Argument Ordering Rules

When mixing argument types, you must define them in this exact order:
  1. Standard positional arguments
  2. *args
  3. Keyword-only arguments
  4. **kwargs

Positional-Only (/) and Keyword-Only (*) Parameters

  • Positional-Only (/): Parameters before / must be passed positionally.
  • Keyword-Only (*): Parameters after * must be passed as keyword arguments.

5. Variable Scope & LEGB Rule

The scope of a variable refers to the region of a program where that variable is accessible.

LEGB Lookup Order

When you reference a variable name, Python searches for it in this strict order:
  1. Local: Inside the current function.
  2. Enclosing: Inside any enclosing (outer) functions.
  3. Global: Top-level variables defined in the module/file.
  4. Built-in: Python’s pre-loaded functions (like len, print).
If not found, Python raises a NameError.

The global and nonlocal Keywords

  • global: Declares that a variable inside a function refers to the global scope, allowing you to modify it.
  • nonlocal: Declares that a variable inside a nested function refers to the enclosing (outer) scope, allowing you to modify it.
Python treats functions as first-class objects, meaning they can be assigned to variables, passed as arguments, returned from other functions, and stored in collections.

Functions as First-Class Objects

Functions can be:
  • Assigned to variables.
  • Passed as arguments.
  • Returned from functions.
  • Accessed using attributes like __name__.

Lambda Functions

A lambda is a small anonymous function consisting of a single expression.
Lambdas are commonly used with functions like map(), filter(), and sorted().
Use lambda functions only for simple expressions. For complex logic, use a normal function.

Variable-Length Arguments (*args and **kwargs)

  • *args collects extra positional arguments into a tuple.
  • **kwargs collects extra keyword arguments into a dictionary.

Closures

A closure is a nested function that remembers variables from its enclosing scope.

Decorators

A decorator extends the behavior of a function without modifying its source code.

Decorators with Arguments

Use *args and **kwargs to support functions with any number of arguments.
Python supports Functional Programming (FP), where functions are treated as first-class objects. In this paradigm, functions can be passed as arguments, returned from other functions, and used to build reusable and declarative code. Functional programming in Python is mainly based on:
  • Declarative Programming
  • Higher-Order Functions

Declarative Programming

Declarative programming focuses on what you want to achieve, while imperative programming focuses on how to achieve it.

Imperative vs Declarative

Imperative (How):
Declarative (What):

Higher-Order Functions

A Higher-Order Function is a function that:
  • Accepts one or more functions as arguments.
  • Returns a function as its result.

Passing Functions as Arguments

Returning Functions

Real-World Example


Built-in Higher-Order Functions

map()

Applies a function to every element of an iterable.
You can also pass a normal function when the logic is more complex.

filter()

Returns only the elements that satisfy a condition.

reduce()

The reduce() function (from the functools module) combines all elements into a single value.

Functional Pipeline Example

The following example combines filter(), map(), and reduce() to compute the sum of squares of even numbers.
The same pipeline can also be written in a single statement.

Pythonic Alternative

Although map(), filter(), and reduce() are useful, Python often provides a simpler and more readable solution using comprehensions and built-in functions.
Use list comprehensions and built-in functions like sum() for better readability. Use map(), filter(), and reduce() when working with functional pipelines or callback-based APIs.