Lambda Expressions
Lambda expressions create anonymous functions in Python. These are concise ways to define single-line functions without using the def keyword. They're particularly useful for simple operations where creating a formal function would be excessive.
The syntax accepts multiple comma-separated parameters and returns the result of a single expression. Here's an example:
sum_values = lambda a, b: a + b
print(sum_values(7, 4)) # Output: 11
Here's a more comprehensive example showing how lambdas can replace traditional functions:
original_list = [5, 6, 7, 8]
transformed_list = []
increment_func = lambda num: num + 2
print(increment_func(3))
transformed_list = [increment_func(item) for item in original_list]
print(transformed_list)
This is equivalent to writing:
original_list = [5, 6, 7, 8]
transformed_list = []
def add_two(value):
value = value + 2
return value
result = add_two(3)
print(result)
transformed_list = []
for item in original_list:
transformed_list.append(add_two(item))
print(transformed_list)
Benefits include rapid creation of simple functions. Limitations involve the restriction to single expressions, making complex logic unsuitable for lambda expressions.
Mapping and Reduction Operations
map and reduce serve as powerful higher-order functions for sequence manipulation.
Map Function
Takes a function and an iterable, applying the function to each element and returning a transformed sequence. This processes every element with the same operation.
values = [2, 4, 6, 8, 10]
doubled_values = map(lambda n: n * 2, values)
print(list(doubled_values)) # Output: [4, 8, 12, 16, 20]
Reduce Function
Applies a function cumulatively to elements, producing a single aggregated result. Requires importing from functools.
from functools import reduce
values = [2, 3, 4, 5, 6]
total_product = reduce(lambda x, y: x * y, values)
print(total_product) # Output: 720
The reduction process works by taking the first two elements (2, 3), multipyling them to get 6, then combining that result with the next element (6 * 4 = 24), continuing untill all elements are processed.
Namespace Organization
Namespaces provide mappings from names to objects, implemented through Python dictionaries. They prevent naming conflicts by maintaining separate contexts.
Each namespace operates independently, allowing identical names across different namespaces without interference.
Types of Namespaces:
- Local: Variables within function boundaries
- Global: Variables accessible throughout the entire module
- Built-in: Predefined Python components
Python follows three primary namespace categories:
- Built-in names: Core Python functions like
abs,len, and exceptions - Global names: Module-level variables including functions, classes, imports
- Local names: Function-specific variables including parameters
Resolution Order:
When accessing variable counter, Python searches in this sequence:
Local → Enclosing → Global → Built-in
If the variable remains unfound, Python raises an error.
Lifecycle:
Namespace existence depends on scope duration. Once execution completes, internal namespace objects become inaccessible from external scopes.
Variable Scoping Rules (LEGB)
Python follows a hierarchical approach when resolving variable references, searching from innermost to outermost scopes.
The four scoping levels include:
- Local (L): Function/method interior variables
- Enclosing (E): Non-local, non-global variables in nested functions
- Global (G): Module-wide variables
- Built-in (B): Predefined Python identifiers
Search progression moves from local to enclosing to global to built-in scopes.
Only modules, classes, and functions (def, lambda) create new scopes. Control structures like if, for, while do not establish new scopes.
Global Scope Examples:
Variables defined at module level have global accessibility:
global_var = 15
def display_global():
print(global_var) # Accesses global variable
display_global() # Output: 15
Local Scope Examples:
Function-defined variables remain accessible only within their defining function:
def outer_function():
local_var = 25
def inner_function():
print(local_var) # Accesses outer function's variable
inner_function()
outer_function() # Output: 25
Enclosing Scope Examples:
Nested functions can access variables from their containing functions:
def parent_scope():
enclosed_var = 35
def child_scope():
print(enclosed_var) # Accesses parent's variable
child_scope()
parent_scope() # Output: 35
Built-in Scope Examples:
Predefined Python functions are globally accessible:
print(len([10, 20, 30])) # Built-in len() function
Python resolves variable names using the LEGB rule: Local, Enclosing, Global, Built-in. If no matching variable exists across all scopes, Python raises a NameError exception.