Functional Programming: Beginner

Databricks processes petabytes of data daily using functional patterns where map() applies the same transformation to millions of records simultaneously, and filter() removes unwanted rows without a single for loop. The data engineering teams at companies like Instacart use these tools to clean, reshape, and validate raw data in pipelines that run thousands of times per day. lambda functions let you define a transformation inline without naming it, keeping pipeline code compact and readable. The map(), filter(), and lambda patterns in this lesson are the building blocks of modern data transformation pipelines.

Defining Functions

Daily Life
Interviews

Build reusable functions with def

Functions are reusable blocks of code that perform a specific task. They help you organize your programs and avoid repeating the same code.

What is a Function?

You have already used functions without realizing it. Every time you write print("Hello") or len("text"), you are calling a function. These are built-in functions that come with Python, created by Python developers to handle common tasks. The print() function displays output to the screen. The len() function calculates the length of a string or collection. You do not need to know how these functions work internally; you just need to know what to give them and what they give back.

1# Using built-in functions you already know
2message = "Hello, Python!"
3print(message)
4print(len(message))
5
6# More built-in functions
7numbers = [5, 2, 8, 1, 9]
8print(max(numbers))
9print(min(numbers))
10print(sum(numbers))
>>>Output
Hello, Python!
14
9
1
25

Each function call follows the same pattern: write the function name, open parentheses, provide any data the function needs (called arguments), and close parentheses. The function processes the arguments and may produce a result you can use.

01
Function Name
Identifies which function to run
02
Parentheses ()
Signal that you are calling the function
03
Arguments
Values inside the parentheses provide input data
04
Return Value
The function may send a result back for you to store or use

Why Create Functions?

Built-in functions cover common operations, but your programs have unique requirements. You might need to calculate taxes for your specific business rules, format names according to your company standards, or validate data in ways Python cannot predict. Creating your own functions lets you package this custom logic and reuse it throughout your program.
Consider a program that needs to calculate the area of rectangles in several places. Without functions, you would repeat the calculation each time:
1# First calculation
2width1 = 5
3height1 = 3
4area1 = width1 * height1
5print("Room 1 area:", area1)
6
7width2 = 10
8height2 = 4
9area2 = width2 * height2
10print("Room 2 area:", area2)
11
12width3 = 7
13height3 = 6
14area3 = width3 * height3
15print("Room 3 area:", area3)
The calculation width * height appears three times. This seems harmless now, but imagine the formula becomes more complex, perhaps adding a margin for waste or converting units. You would need to update every location where you copied the formula. Functions eliminate this duplication by letting you define the logic once and call it from anywhere.
Reusability
Reusability
Write code once and call it from anywhere in your program
Maintainability
Maintainability
Fix bugs in a single place instead of hunting down every copy
Readability
Readability
Give complex logic a meaningful name that explains its purpose
Testability
Testability
Test each function independently to catch errors early
Organization
Organization
Break large problems into smaller, manageable pieces

To create a function, use the def keyword (short for "define"), followed by the function name, parentheses, and a colon. The lines of code that belong to the function must be indented. This indented block is called the function body, and it contains the code that runs when you call the function.

1# Define a simple function
2def greet():
3 print("Hello, World!")
4 print("Welcome to Python functions!")
5
6print("Before calling the function")
7
8greet()
9
10print("After calling the function")
>>>Output
Before calling the function
Hello, World!
Welcome to Python functions!
After calling the function

Notice the order of output. The code inside the function only runs when you call it with greet(). Defining a function is like writing a recipe; calling it is like actually cooking the dish. You can call a function as many times as you want, and each call executes the function body from the beginning.

1def announce():
2 print("*" * 20)
3 print("IMPORTANT MESSAGE")
4 print("*" * 20)
5
6announce()
7print("First message")
8announce()
9print("Second message")
10announce()
>>>Output
********************
IMPORTANT MESSAGE
********************
First message
********************
IMPORTANT MESSAGE
********************
Second message
********************
IMPORTANT MESSAGE
********************

Anatomy of a Function

Every function definition has the same structure. Understanding each part helps you write functions correctly and read other people's code:
1def function_name():
2 # Function body
3 # Indented
4 statement_1
5 statement_2
6 statement_3
7
8# Outside function
defname():body
def
Keyword
Tells Python: new function
name
Identifier
How you call the function
()
Parentheses
Required, even if empty
:
Colon
Ends the function header
body
Indented Block
Runs when function called

Function Naming Conventions

Function names follow the same rules as variable names. They must start with a letter or underscore, can contain letters, numbers, and underscores, and cannot be Python keywords. Beyond these rules, there are strong conventions that make code readable:
Good Function Names
  • calculate_area
  • format_user_name
  • validate_email
  • convert_temperature
  • get_total_price
Poor Function Names
  • doStuff
  • f
  • myFunction
  • process
  • x
Good function names are lowercase with words separated by underscores (called snake_case). They use verbs or verb phrases that describe what the function does. Someone reading calculate_area immediately understands the purpose without looking at the code inside.
TIP
A function name should describe what it does, not how it does it. "calculate_tax" is better than "multiply_by_rate" because it describes the purpose, not the implementation detail that might change.

Indentation is Mandatory

Python uses indentation to determine which code belongs to a function. Every line in the function body must be indented by the same amount (typically four spaces). Inconsistent indentation causes errors:
1# CORRECT: Consistent indentation
2def greet():
3 print("Hello!")
4 print("Welcome!")
5 print("Have a great day!")
6
7# WRONG: Would cause IndentationError
8def greet_broken():
9 print("Hello!")
10 # Error! Wrong indentation
11 print("This line has wrong indentation!")
12 print("Have a great day!")
When you reduce the indentation back to the original level, you signal the end of the function body. The next unindented line is outside the function and runs independently of any function call.
Python Quiz

> Build a function that formats a test score as a percentage string. Pick the function that rounds to one decimal place and the function that converts the number to text for concatenation.

def format_score(score):
    rounded = ___(score, 1)
    return ___(rounded) + "%"

print(format_score(87.456))
abs
int
round
float
str
Functions are the foundation of organized Python code. Every professional codebase consists largely of function definitions and function calls that compose to produce complex behavior from simple pieces.
Python uses indentation to define function bodies, making the structure visually clear. The function body runs only when you call the function, not when you define it, just as a recipe only produces food when you cook it.
Good function names describe what the function does, not how it does it. A name like calculate_tax communicates intent instantly; a name like multiply_by_rate exposes an implementation detail that might change.

Function Parameters

Daily Life
Interviews

Pass data into functions with params

Most functions need input data to work with. A function that calculates area needs to know the dimensions. A function that formats names needs to know the name. Parameters are variables that receive values when you call the function. They appear inside the parentheses in the function definition and act as placeholders for the actual values you will provide.
Two terms that beginners often mix up are parameters and arguments. They refer to different sides of the same coin.
ParameterArgument
Parameter
In Definition
Variable in the def line
Argument
In Call
Actual value you pass in
1# name is a PARAMETER - receives a value
2def greet(name):
3 print("Hello, " + name + "!")
4 print("Nice to meet you, " + name + ".")
5
6# "Alice" is an ARGUMENT
7greet("Alice")
8print("---")
9greet("Bob")
10print("---")
11greet("Charlie")
>>>Output
Hello, Alice!
Nice to meet you, Alice.
---
Hello, Bob!
Nice to meet you, Bob.
---
Hello, Charlie!
Nice to meet you, Charlie.

When you call greet("Alice"), Python assigns the value "Alice" to the parameter name. Inside the function, name behaves like any other variable, holding that value for the duration of the function call.

Multiple Parameters

Functions can accept multiple parameters, separated by commas. When calling the function, you must provide arguments in the same order as the parameters are defined:
1def calculate_area(width, height):
2 area = width * height
3 print("Width: " + str(width))
4 print("Height: " + str(height))
5 print("Area: " + str(area))
6 print("---")
7
8# Arguments must match parameter order
9calculate_area(5, 3)
10calculate_area(10, 4)
11calculate_area(7, 6)
>>>Output
Width: 5
Height: 3
Area: 15
---
Width: 10
Height: 4
Area: 40
---
Width: 7
Height: 6
Area: 42
---
The first argument becomes the first parameter, the second argument becomes the second parameter, and so on. This is called positional matching because the position determines which parameter receives which value.

Default Parameter Values

Sometimes you want a parameter to have a sensible default value that the caller can override if needed. This makes parameters optional. Default values are specified with an equals sign in the function definition:
1def greet(name, greeting="Hello"):
2 print(greeting + ", " + name + "!")
3
4# Using the default greeting
5greet("Alice")
6
7# Providing a custom greeting
8greet("Bob", "Hi")
9greet("Charlie", "Good morning")
10greet("Diana", "Welcome")
>>>Output
Hello, Alice!
Hi, Bob!
Good morning, Charlie!
Welcome, Diana!

The parameter greeting has a default value of "Hello". When you call greet("Alice") with only one argument, greeting uses its default. When you provide a second argument, that value overrides the default.

TIP
Parameters with default values must come after parameters without defaults. Writing def greet(greeting="Hello", name) causes a syntax error because Python cannot determine which argument goes where.

Flexible Formatting Example

Default parameters are perfect for functions that need flexibility. Here is a formatting function where most calls use the defaults, but callers can customize when needed:
1def format_price(amount, currency="$", decimals=2):
2 formatted = round(amount, decimals)
3 return currency + str(formatted)
4
5# Most common use - just the amount
6print(format_price(19.99))
7print(format_price(100))
8
9# Override currency
10print(format_price(50, "EUR "))
11
12# Override both
13print(format_price(1234.5678, "GBP ", 3))
>>>Output
$19.99
$100
EUR 50
GBP 1234.568
Callers who just need dollar formatting with two decimals pass only the amount. Callers with special needs can override one or both defaults. This pattern appears throughout Python's standard library.

Wrong Number of Arguments

If you call a function with too few or too many arguments, Python raises a TypeError. The error message tells you exactly how many arguments were expected versus how many you provided:
1def greet(first_name, last_name):
2 print("Hello, " + first_name + " " + last_name + "!")
3
4# Correct: provides both required arguments
5greet("Ada", "Lovelace")
6
7# Wrong: missing the second argument
8# greet("Ada")
9# TypeError: missing required argument
10
11# Wrong: too many arguments
12# greet("Ada", "Lovelace", "PhD")
13# TypeError: takes 2 arguments but 3 given
Read these error messages carefully. They tell you the function name, how many arguments it expects, and how many you provided. This information helps you quickly identify and fix the mismatch.
Test your understanding of parameters and default values by experimenting with different function calls below.
Fill in the Blank

> You are defining a greet function with a default greeting parameter. Pick a default value and see how it affects the output when the caller omits the argument.

def greet(name, greeting=):
    print(greeting + ", " + name)

greet("Alice")
Parameters make functions flexible. A function with well-chosen parameters can be reused in many different contexts without any changes to its internal logic.
Default parameter values are a powerful technique for making functions easier to use. They let callers omit arguments they do not need to customize, reducing boilerplate in common cases.
Parameters without defaults are required; parameters with defaults are optional. Required parameters must always come before optional ones in the function signature so Python can unambiguously match arguments to parameters.

Return Values

Daily Life
Interviews

Send results back with return values

Functions can send data back to the caller using the return statement. This is how functions produce results that you can store in variables, use in calculations, or pass to other functions. Return values transform functions from mere action performers into calculators that produce usable results.

1def calculate_area(width, height):
2 return width * height
3
4# Store the returned value in a variable
5area1 = calculate_area(5, 3)
6area2 = calculate_area(10, 4)
7
8print("First area: " + str(area1))
9print("Second area: " + str(area2))
10print("Combined area: " + str(area1 + area2))
11
12# Use directly in expressions
13total_cost = calculate_area(12, 8) * 25
14print("Cost at $25 per sq unit: $" + str(total_cost))
>>>Output
First area: 15
Second area: 40
Combined area: 55
Cost at $25 per sq unit: $2400

The return statement immediately exits the function and sends the specified value back to where the function was called. That value replaces the function call in the expression, as if you had written the value directly.

Return vs Print: Key Diff

Beginners often confuse print() and return. They seem similar because both involve output, but they serve completely different purposes. Understanding this distinction is fundamental to writing useful functions:

print()
  • Displays text on screen
  • For human consumption only
  • Function returns None
  • Cannot use the value later
  • Side effect, not a result
return
  • Sends value back to caller
  • For program consumption
  • Value can be stored and used
  • Enables further calculations
  • Actual function result
1def add_with_print(a, b):
2 # Shows the sum but returns nothing
3 print(a + b)
4
5def add_with_return(a, b):
6 # Returns the sum for further use
7 return a + b
8
9# Try to use the results
10result1 = add_with_print(3, 5)
11result2 = add_with_return(3, 5)
12
13print("result1 is: " + str(result1))
14print("result2 is: " + str(result2))
15print("result2 doubled: " + str(result2 * 2))
>>>Output
8
result1 is: None
result2 is: 8
result2 doubled: 16

add_with_print displays 8 on the screen but returns None, so result1 is useless. add_with_return does not display anything but returns 8, which we can store, display, or use in further calculations.

Functions Without Return

If a function does not have a return statement, or if return is used without a value, the function automatically returns None. None is Python's special value representing "nothing" or "no value."

1def say_hello():
2 print("Hello!")
3 # No return statement
4
5def say_goodbye():
6 print("Goodbye!")
7 return
8
9result1 = say_hello()
10result2 = say_goodbye()
11
12print("Result 1:", result1)
13print("Result 2:", result2)
14print("Both are None:", result1 is None and result2 is None)
>>>Output
Hello!
Goodbye!
Result 1: None
Result 2: None
Both are None: True
Functions without return values are used for their "side effects" such as printing messages, writing to files, or modifying data. They perform actions rather than computing results. Both patterns are valid; the choice depends on the function's purpose.

Return Exits Immediately

When Python encounters a return statement, it immediately exits the function. Any code after the return statement never runs. This is useful for early exits when you have already determined the result:

1def check_age(age):
2 if age < 0:
3 return "Invalid: age cannot be negative"
4 if age < 18:
5 return "Minor"
6 if age < 65:
7 return "Adult"
8 return "Senior"
9
10print(check_age(-5))
11print(check_age(15))
12print(check_age(30))
13print(check_age(70))
>>>Output
Invalid: age cannot be negative
Minor
Adult
Senior
Each condition checks the age and returns immediately if it matches. The function never runs more code than necessary. When a return is executed, Python skips all remaining code in the function.

Scope and Variables

Daily Life
Interviews

Control variable visibility in code

Scope determines where a variable exists and can be accessed. Understanding scope prevents bugs where variables unexpectedly have wrong values or do not exist when you expect them to. Python has two main scopes relevant to functions: local scope (inside a function) and global scope (outside all functions).
Scope Definition
  • Local scope - variables created inside a function, only visible there
  • Global scope - variables created outside all functions, visible everywhere
  • A variable's scope is determined by where it is created

Local Variables

Variables created inside a function are local to that function. They are created when the function starts running and destroyed when the function finishes. They do not exist outside the function and cannot be accessed from elsewhere:
1def calculate():
2 result = 100
3 multiplier = 5
4 total = result * multiplier
5 print("Inside function:", total)
6
7calculate()
8# print(result) # NameError! result does not exist here
9# print(multiplier) # NameError! multiplier does not exist here
10# print(total) # NameError! total does not exist here
This isolation is intentional and beneficial. Each function has its own private workspace. You can use the same variable name in different functions without conflict because each function has its own local scope.
1def function_one():
2 # x is local to function_one
3 x = 10
4 print("function_one x:", x)
5
6def function_two():
7 # x is local to function_two, completely separate
8 x = 99
9 print("function_two x:", x)
10
11function_one()
12function_two()
13function_one()
>>>Output
function_one x: 10
function_two x: 99
function_one x: 10

Global Variables

Variables created outside any function are global. They exist for the entire program and can be read from inside functions. However, you cannot modify them from inside a function without special syntax (which we will cover in the intermediate lesson).
1TAX_RATE = 0.08
2COMPANY_NAME = "ACME Corp"
3
4def calculate_tax(price):
5 # Can READ global variables
6 tax = price * TAX_RATE
7 return tax
8
9def print_receipt(item, price):
10 # Can READ globals too
11 tax = calculate_tax(price)
12 total = price + tax
13 print(COMPANY_NAME)
14 print("-" * 20)
15 print(item + ": $" + str(price))
16 print("Tax: $" + str(tax))
17 print("Total: $" + str(total))
18
19print_receipt("Widget", 100)
>>>Output
ACME Corp
--------------------
Widget: $100
Tax: $8.0
Total: $108.0
Global variables named in ALL_CAPS indicate constants that should not change. Functions can read these values freely, making it easy to share configuration across your program.

Parameters as Local Vars

Parameters are local variables too. When you call a function, Python creates local variables from the parameters and assigns the argument values to them. Modifying a parameter inside the function does not affect variables outside:
1def attempt_to_modify(x):
2 print("Inside function, before:", x)
3 # Modifies the local x only
4 x = x * 2
5 print("Inside function, after:", x)
6
7number = 5
8print("Before function call:", number)
9attempt_to_modify(number)
10# Unchanged!
11print("After function call:", number)
>>>Output
Before function call: 5
Inside function, before: 5
Inside function, after: 10
After function call: 5

The parameter x inside the function is a separate variable that happens to start with the same value as number. Changing x does not change number. This is called pass by value for simple types like numbers and strings.

TIP
This behavior is usually what you want. Functions that do not modify external state are easier to understand, test, and debug. Use return values to send results back instead of modifying outside variables.

Scope Lookup Order

When you use a variable name, Python searches for it in order: first local scope, then enclosing scopes (for nested functions), then global scope, then built-in scope. It uses the first match it finds:
1x = "global"
2
3def outer():
4 x = "outer"
5
6 def inner():
7 x = "inner"
8 print("inner sees:", x)
9
10 inner()
11 print("outer sees:", x)
12
13outer()
14print("global sees:", x)
>>>Output
inner sees: inner
outer sees: outer
global sees: global
Each scope has its own x. The inner function finds its local x first and uses that. The outer function finds its local x. The global code finds the global x. They coexist without interfering.
Python Quiz

> Write a function that returns the largest value and the count of items from a list. Pick the builtin that finds the maximum and the one that measures the length.

def get_stats(numbers):
    biggest = ___(numbers)
    count = ___(numbers)
    return biggest, count

top, n = get_stats([4, 9, 2, 7])
print(top)
print(n)
len
type
min
sum
max
Understanding scope prevents a whole class of subtle bugs where variables unexpectedly share or shadow each other. Local variables created inside a function are destroyed when the function returns, keeping each function call isolated.
Global variables are best used for true constants that do not change during the program, like configuration settings. Passing values through parameters and returning results through return values produces more predictable, testable functions.
When Python searches for a variable name, it looks in local scope first, then enclosing scopes, then global scope, then built-in scope. Understanding this lookup order explains why a local variable with the same name as a global will always shadow the global inside that function.

Type Hints and Documentation

Daily Life
Interviews

Annotate functions with type hints

As programs grow larger and teams work together, it becomes important to document what types of values functions expect and return. Python provides type hints, which are annotations that describe expected types. Type hints do not change how code runs; they are documentation for humans and tools.

Basic Type Hints

Add type hints after parameter names with a colon and the type. Add return type hints after the closing parenthesis with -> followed by the type:

1def calculate_area(width: float, height: float) -> float:
2 return width * height
3
4def greet(name: str) -> str:
5 return "Hello, " + name + "!"
6
7def is_adult(age: int) -> bool:
8 return age >= 18
9
10def print_message(message: str) -> None:
11 print(message)

These hints tell readers that calculate_area expects two float numbers and returns a float. greet expects a str and returns a str. is_adult expects an int and returns a bool (True or False).

Common Type Hints
  • int: Whole numbers like 5, -10, 0
  • float: Decimal numbers like 3.14, -2.5
  • str: Text strings like "hello"
  • bool: Boolean values True or False
  • None: The special "no value" value
  • list: A list of items
  • dict: A dictionary of key-value pairs

Type Hints Are Not Enforced

Python does not enforce type hints at runtime. You can pass a str where the hint says int, and Python will try to run the code. This differs from statically-typed languages like Java or TypeScript. Type hints are purely informational:

1def double(x: int) -> int:
2 return x * 2
3
4print(double(5))
5print(double("ab"))
6
>>>Output
10
abab

The type hint says int, but Python happily multiplies a str by 2 (which repeats it). Type hints are for documentation and for external tools like type checkers (mypy) that analyze code before you run it.

Why Use Type Hints?

Type hints provide significant benefits for code quality and maintainability, especially in larger codebases and team environments.
Benefits of Type Hints
  • Documentation: Readers immediately know expected types
  • IDE support: Code editors provide better autocomplete
  • Error prevention: Type checkers catch bugs before runtime
  • Refactoring: Easier to change code with type information
  • Team communication: Clear contracts between functions
Adopting type hints early builds a habit that pays off as your codebase grows.
TIP
Start using type hints even in personal projects. They make your code self-documenting and help you catch bugs early. Many professional codebases require type hints for all function signatures.
The broader Python ecosystem has invested heavily in type hinting infrastructure.

Common Mistakes

Everyone makes these mistakes when learning functions. Knowing about them helps you recognize and fix them quickly when they happen:

Forgetting to Call Function

Defining a function does not run it. You must call the function with parentheses to execute its code:
Wrong
  • def greet():
  • print("Hello!")
  • # Function defined but never called
  • # Nothing prints!
Correct
  • def greet():
  • print("Hello!")
  • greet() # Call with parentheses
  • # Prints "Hello!"

Forgetting return Statement

If you want to use a function's result, you must return it. Calculating a value without returning it means the result is lost:
Wrong
  • def add(a, b):
  • result = a + b
  • # Forgot return!
  • total = add(3, 5) # total is None
Correct
  • def add(a, b):
  • return a + b
  • total = add(3, 5) # total is 8
The mistake of forgetting return is very common among beginners. Try fixing the bug below where a function calculates a value but accidentally loses it.
Debug Challenge

> This function calculates the area of a rectangle but prints it instead of returning it. The caller gets None because there is no return statement.

The function prints 15 but result is None because the function never returns the value.

Calling Before Defining

Python executes code from top to bottom. A function must be defined before the line that calls it:
1# greet() # NameError
2
3def greet():
4 print("Hello!")
5
6greet()

Reference vs Call Confusion

greet (without parentheses) is the function object itself. greet() (with parentheses) calls the function. They are very different:

1def greet():
2 return "Hello!"
3
4print(greet)
5
6print(greet())
>>>Output
<function greet at 0x...>
Hello!
PUTTING IT ALL TOGETHER

> You are a data analyst at Salesforce building a reusable ETL utility that cleans contact records across ten regional CSV files, each requiring the same standardization logic applied consistently without duplicating code.

def packages the record-cleaning logic once with a descriptive name so every regional file calls the same standardization routine without copy-pasting.
Function parameters accept each regional dataset as an argument, letting the same function body operate on different inputs without hardcoded file paths.
return passes the cleaned record list back to the caller so the result can be written to the output file or passed to the next pipeline stage.
Scope and variable rules ensure counters and temporary strings inside the cleaning function stay isolated and do not accidentally overwrite variables in the outer pipeline script.
KEY TAKEAWAYS
Use def to define functions that package reusable code
Parameters receive values passed as arguments when calling
Default values (param=value) make parameters optional
return sends a value back; without it, the function returns None
Local variables exist only inside their function
Global variables can be read but not modified without the global keyword
Type hints document expected types but are not enforced at runtime
Functions must be defined before the code that calls them

Building reusable blocks of logic

Category
Python
Difficulty
beginner
Duration
37 minutes
Challenges
0 hands-on challenges

Topics covered: Defining Functions, Function Parameters, Return Values, Scope and Variables, Type Hints and Documentation

Lesson Sections

  1. Defining Functions

    Functions are reusable blocks of code that perform a specific task. They help you organize your programs and avoid repeating the same code. What is a Function? Why Create Functions? Built-in functions cover common operations, but your programs have unique requirements. You might need to calculate taxes for your specific business rules, format names according to your company standards, or validate data in ways Python cannot predict. Creating your own functions lets you package this custom logic a

  2. Function Parameters

    Most functions need input data to work with. A function that calculates area needs to know the dimensions. A function that formats names needs to know the name. Parameters are variables that receive values when you call the function. They appear inside the parentheses in the function definition and act as placeholders for the actual values you will provide. Two terms that beginners often mix up are parameters and arguments. They refer to different sides of the same coin. Multiple Parameters Func

  3. Return Values

    Return vs Print: Key Diff Functions Without Return Functions without return values are used for their "side effects" such as printing messages, writing to files, or modifying data. They perform actions rather than computing results. Both patterns are valid; the choice depends on the function's purpose. Return Exits Immediately Each condition checks the age and returns immediately if it matches. The function never runs more code than necessary. When a return is executed, Python skips all remainin

  4. Scope and Variables

    Scope determines where a variable exists and can be accessed. Understanding scope prevents bugs where variables unexpectedly have wrong values or do not exist when you expect them to. Python has two main scopes relevant to functions: local scope (inside a function) and global scope (outside all functions). Local Variables Variables created inside a function are local to that function. They are created when the function starts running and destroyed when the function finishes. They do not exist ou

  5. Type Hints and Documentation (concepts: pyTypeHints)

    As programs grow larger and teams work together, it becomes important to document what types of values functions expect and return. Python provides type hints, which are annotations that describe expected types. Type hints do not change how code runs; they are documentation for humans and tools. Basic Type Hints Type Hints Are Not Enforced Why Use Type Hints? Type hints provide significant benefits for code quality and maintainability, especially in larger codebases and team environments. Adopti