Programming Fundamentals
Functions
**Puzzle:** There is code for calculating a discount. It is needed in 20 places in the program. Copy it 20 times? And if the formula needs to change - edit it in 20 places? Functions solve this problem once and for all.
A function is a named block of code that can be called as many times as needed. Built-in functions like print(), len(), range() follow the same mechanics. This lesson covers how to build custom ones.
Цели урока
- Understand what a function is and why it is needed
- Learn to create functions with parameters
- Master returning values (return)
- Understand the difference between parameters and arguments
Предварительные знания
- Variables and types (lesson 3)
- Conditionals (lesson 6)
- Loops (lesson 7)
Every application is a set of functions. Tapped the "Buy" button? The function process_payment() was called. Sent a message? The function send_message(). Functions are the building blocks of programs.
- **APIs**: every endpoint is a function on the server
- **Libraries**: pandas, numpy, requests - collections of functions
- **Games**: move_player(), check_collision(), render_frame()
- **Business**: calculate_tax(), send_invoice(), generate_report()
From Church's lambda calculus to JavaScript arrow functions
The idea of a function as an object is older than any programming language. In 1936 Alonzo Church at Princeton formalized lambda calculus: a mathematical model of computation built entirely on anonymous functions and applying them to values. At the same time Alan Turing (Church's student) showed that lambda calculus and the Turing machine are equally powerful. On the practical side, the subroutine as a reusable block came out of Grace Hopper's work on UNIVAC in the late 1940s, and she was the first to call the library of reusable blocks subroutines. In 1958 John McCarthy at MIT built Lisp, where functions became first-class objects: pass them as arguments, return them from other functions, store them in variables. In 1972 Dennis Ritchie added function pointers to C, the first practical taste of first-class functions in the mainstream. In 1995 Brendan Eich built JavaScript in ten days with functions as objects, which set up the functional style on the web. In 2015 ES6 added arrow functions: const f = x => x * 2, lexical this, tight syntax. Today anonymous functions are everywhere: lambda in Python, fn in Rust, closures in Kotlin and Swift. Church's 1936 idea now runs in every browser, every server, every app.
Creating a function: def
**def** (define) - the keyword for creating a function. After it comes the function name and parentheses.
The simplest function
Definition and call
```python # Define the function def greet(): print("Hello!") print("How are you?") # Call the function greet() # Hello! How are you? greet() # Can be called as many times as needed! ``` **Structure:** 1. `def` - keyword 2. `greet` - function name (like a variable, snake_case) 3. `()` - parentheses for parameters (empty for now) 4. `:` - colon at the end of the line 5. Function body - indented
**Definition ≠ Execution!** The code inside a function does NOT run until the function is called. `def greet():` simply creates the function, while `greet()` calls it.
What happens when this code runs? ```python def hello(): print("Hello") ```
Parameters: input data
**Parameters** - variables in the parentheses when defining a function. They receive values when the function is called.
Function with a parameter
Personalized greeting
```python # name - parameter (placeholder) def greet(name): print(f"Hello, {name}!") # When calling, pass an argument greet("Alice") # Hello, Alice! greet("Bob") # Hello, Bob! # Multiple parameters def greet_full(first_name, last_name): print(f"Good day, {first_name} {last_name}!") greet_full("John", "Smith") # Good day, John Smith! ```
**Parameter vs Argument:** - **Parameter** - the variable in the definition: `def greet(name)` - **Argument** - the specific value when calling: `greet("Alice")`
Calculator function
Calculation with parameters
```python def calculate_area(width, height): area = width * height print(f"Area: {area}") calculate_area(5, 3) # Area: 15 calculate_area(10, 2) # Area: 20 # The order of arguments matters! calculate_area(3, 5) # Same result, arguments in different order ```
What will the code print? ```python def add(a, b): print(a + b) add(3, 5) ```
return: returning a result
**return** - returns a value from the function. The function becomes a "machine" that takes input data and produces a result.
Function with return
return instead of print
```python # Without return (only prints) def add_print(a, b): print(a + b) # Just displays # With return (returns the value) def add(a, b): return a + b # Returns the result # Difference: add_print(3, 5) # Prints 8, but the result is "lost" result = add(3, 5) # result = 8, can be used further! print(result * 2) # 16 total = add(add(1, 2), add(3, 4)) # 1+2 + 3+4 = 10 ```
**return stops the function!** Code after return will not run. This can be used for early exit.
Early return
Exit on condition
```python def divide(a, b): if b == 0: return None # Early exit on error return a / b print(divide(10, 2)) # 5.0 print(divide(10, 0)) # None (division by 0) ```
print() and return are the same thing
print() outputs to the screen, return - returns a value for further use
print() is a side effect (output). return is the function's result, which can be saved to a variable, passed to another function, or used in calculations.
What will be in x? ```python def mystery(n): return n * 2 print("Done") x = mystery(5) ```
Default values
Parameters can be given **default values**. If an argument is not passed - the default is used.
Parameters with default values
Optional arguments
```python def greet(name, greeting="Hello"): print(f"{greeting}, {name}!") greet("Alice") # Hello, Alice! greet("Bob", "Good day") # Good day, Bob! greet("Carol", greeting="Hey") # Hey, Carol! # Practical example def power(base, exponent=2): return base ** exponent print(power(5)) # 25 (5²) print(power(5, 3)) # 125 (5³) ```
**Rule:** parameters with default values must come AFTER regular parameters. `def f(a=1, b)` - error!
Named arguments
Explicit specification of the parameter
```python def create_user(name, age, city="Unknown", active=True): print(f"{name}, {age} years old, {city}, active: {active}") # Positional arguments (in order) create_user("Alice", 25, "London", False) # Named arguments (in any order) create_user(name="Bob", age=30, active=False) create_user("Carol", 28, active=False) # Mixed ```
What will it print? ```python def f(a, b=10): return a + b print(f(5)) ```
Returning multiple values
Python allows returning multiple values separated by commas. Technically this is a tuple.
Multiple return
Several values at once
```python def min_max(numbers): return min(numbers), max(numbers) # Unpacking the result minimum, maximum = min_max([3, 1, 4, 1, 5]) print(f"Min: {minimum}, Max: {maximum}") # Min: 1, Max: 5 # Or as a tuple result = min_max([3, 1, 4, 1, 5]) print(result) # (1, 5) # Practice: division with remainder def divmod_custom(a, b): quotient = a // b remainder = a % b return quotient, remainder q, r = divmod_custom(17, 5) print(f"17 = 5 × {q} + {r}") # 17 = 5 × 3 + 2 ```
What will be in a and b? ```python def swap(x, y): return y, x a, b = swap(1, 2) ```
Documenting functions
**Docstring** - a documentation string at the beginning of a function. It describes what the function does, what parameters it takes, and what it returns.
Docstring in action
Document your functions
```python def calculate_bmi(weight, height): """ Calculates the Body Mass Index (BMI). Args: weight: Weight in kilograms height: Height in meters Returns: BMI as a float Example: >>> calculate_bmi(70, 1.75) 22.86 """ return weight / (height ** 2) # Access the documentation print(calculate_bmi.__doc__) help(calculate_bmi) # Pretty output in the console ```
In IDEs (VS Code, PyCharm), the docstring is shown when hovering over a function. Write them for functions that will be reused!
Where is the docstring placed in a function?
Connection to other topics
Functions sit at the base of almost every programming abstraction:
- Recursion — A function calling itself, replacing loops with explicit task decomposition
- Scope — Parameters and locals live in the function's stack frame
- Objects — Methods are functions bound to an object through self
- Refactoring — Extract Function is the most common move: split long code into small functions
Summary
- def creates a named function: name, parameters, indented body
- Parameters are the variables in the definition; arguments are the actual values at the call site
- return hands back a value and ends the function on the spot; without return the function returns None
- Default values make parameters optional and must come after the required ones
- Named arguments (name=value) let you pass parameters in any order
- A pure function depends only on its arguments and has no side effects, which makes it easier to test
Вопросы для размышления
- How does the single-responsibility principle for functions affect code testability?
- What distinguishes a pure function from one with side effects, and why does this matter during refactoring?
- What is considered an optimal function size, and why are overly long functions harder to maintain?
Связанные уроки
- prog-06-conditionals — Functions contain branching to vary their behavior
- prog-10-scope — Each function call creates its own variable scope
- prog-09-recursion — Recursion is a function calling itself
- la-07-matrix-multiply — A function maps inputs to outputs like a transformation
- mm-02-first-principles
- alg-01-big-o