Python Tutorial for Beginners 8: Functions
Based on Corey Schafer's video on YouTube. If you like this content, support the original creators by watching, liking and subscribing to their content.
Define functions with `def` and use parentheses to execute them; parentheses are what trigger the function’s code.
Briefing
Functions in Python are reusable blocks of instructions defined with `def` that can take inputs (parameters) and optionally produce outputs (return values). The core practical payoff is maintainability: once logic lives in one place, it can be called repeatedly and updated once when requirements change.
A first function can be created with `def` and a name, followed by parentheses for parameters. If the function body is intentionally empty, `pass` prevents syntax errors while leaving room to fill in later. Execution depends on calling the function: writing the function name alone refers to the function object (showing a memory location), while adding parentheses actually runs it. When a function doesn’t return anything, Python yields `None`, which shows up when the call is printed.
Adding code inside the function turns it into a tool that performs work. A simple example prints a greeting from inside the function. That leads directly to the “don’t repeat yourself” principle (DRY): instead of copying the same print statement across many lines, the program can call the same function multiple times. If a boss later changes punctuation from `!` to `.`, updating the function once updates every call site—whether there are four lines or hundreds spread across files.
The next step is returning data rather than just printing it. Using `return` makes the function call evaluate to the returned value, so the result can be assigned, printed, or fed into other operations. A helpful mental model treats a function like a black box: focus on inputs and the output it returns, not the internal mechanics. This matters because returned values behave like normal data types. For instance, if a function returns a string, string methods such as `.upper()` can be chained onto the function call result.
Parameters customize behavior. Introducing a required parameter like `greeting` forces callers to supply an argument; omitting it triggers a “missing required positional argument” error. Parameters can also have defaults, such as `name='...'`, allowing calls to succeed even when that argument isn’t provided. Defaulted parameters make functions more flexible while keeping call sites concise.
Python also enforces ordering rules: required positional arguments must come before keyword arguments. For more advanced flexibility, `*args` and `**kwargs` accept an arbitrary number of positional and keyword arguments. Inside such a function, `args` arrives as a tuple of positional values, while `kwargs` arrives as a dictionary of keyword values. The same syntax can be used in reverse when calling a function: `*` unpacks a list into positional arguments, and `**` unpacks a dictionary into keyword arguments.
To tie everything together, the tutorial walks through two small functions modeled after Python’s standard library style: `isLeap` determines whether a year is a leap year using divisibility rules, and `daysInMonth` returns the number of days in a given month, including the February leap-year exception. By running these functions with specific inputs (e.g., 2017 vs. 2020, February month=2), the logic demonstrates how arguments drive return values and how multiple functions can cooperate to produce correct results.
Cornell Notes
Python functions package instructions into reusable blocks defined with `def`. Calling a function runs it; omitting parentheses prints the function object instead. If a function doesn’t use `return`, the call evaluates to `None`; using `return` makes the function call equal to the returned value, enabling chaining like `hello().upper()` when the return value is a string. Parameters can be required or have defaults, and missing required arguments raise errors. For variable inputs, `*args` collects positional arguments into a tuple and `**kwargs` collects keyword arguments into a dictionary, and `*`/`**` can also unpack lists/dicts when calling functions.
What’s the practical difference between referencing a function and executing it in Python?
Why does returning values matter more than printing inside a function?
How do required parameters and default parameters change function calls?
What do `*args` and `**kwargs` do, and what types do they become inside the function?
How does argument unpacking work when calling a function with `*` and `**`?
How do the leap-year and days-in-month examples demonstrate inputs driving outputs?
Review Questions
- When does a Python function call evaluate to `None`, and how can you change that behavior?
- How do default parameter values affect whether a function call raises an error?
- Explain the difference between `*args` and `**kwargs`, including what data types they become inside the function.
Key Points
- 1
Define functions with `def` and use parentheses to execute them; parentheses are what trigger the function’s code.
- 2
Use `pass` to create an empty function body without causing errors.
- 3
Avoid repeating logic across the codebase by calling the same function multiple times (DRY).
- 4
Use `return` to make function calls evaluate to useful values rather than relying on printing.
- 5
Required parameters must be provided; default parameters allow calls to omit those arguments.
- 6
Follow Python’s argument ordering rules: required positional arguments come before keyword arguments.
- 7
Use `*args` and `**kwargs` to accept variable numbers of positional and keyword arguments, and use `*`/`**` to unpack lists and dictionaries when calling.