Anonymous Functions
In Python, small anonymous functions can be created using the lambda keyword. Unlike standard functions defined with def, lambda functions are restricted to a single expression and do not require a name. The syntax follows the pattern: lambda arguments: expression. These are often used when a function object is required for a short period, typically as an argument to higher-order functions.
Built-in Functions for Iterables
Several built-in functions work seamlessly with lambda expressions to process data sequences efficiently.
map(): This function applies a given function to every item of an iterable (such as a list) and returns a map object (an iterator).
nums = [1, 2, 3, 4, 5, 6]
squared = map(lambda x: x ** 2, nums)
print(list(squared)) # Output: [1, 4, 9, 16, 25, 36]zip(): Used to combine multiple iterables into a single iterator of tuples. If the input iterables are of uneven length, the iterator stops when the shortest input iterable is exhausted.
keys = ['name', 'age', 'job']
values = ['Alice', 30, 'Engineer']
pairs = zip(keys, values)
print(dict(pairs)) # Output: {'name': 'Alice', 'age': 30, 'job': 'Engineer'}max() and min(): These functions return the largest or smallest item in an iterable. The key parameter allows for custom comparison logic using a lambda function.
salaries = {'manager': 5000, 'developer': 8000, 'director': 12000}
highest_paid = max(salaries, key=lambda k: salaries[k])
print(highest_paid) # Output: 'director'filter(): This function constructs an iterator from elements of an iterable for which a function returns true.
numbers = range(1, 21)
# Filter for odd numbers
odds = filter(lambda n: n % 2 != 0, numbers)
print(list(odds)) # Output: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]Iterables and Iterators
An iterable is any Python object capable of returning its members one at a time, permitting it to be iterated over in a loop. Common examples include lists, tuples, strings, and dictionaries. Internally, an object is iterable if it implements the __iter__() method.
An iterator is an object that represents a stream of data. It is the object returned by calling __iter__() on an iterable. An iterator must implement two methods: __iter__() (which returns the iterator object itself) and __next__() (which returns the next value in the stream). When no more data is available, __next__() raises a StopIteration exception.
data = [10, 20, 30]
# Convert iterable to iterator
iter_obj = iter(data)
print(next(iter_obj)) # Output: 10
print(next(iter_obj)) # Output: 20
print(next(iter_obj)) # Output: 30The Internal Mechanics of For Loops
A for loop in Python is essentially syntactic sugar that simplifies the process of iterating. The mechanism follows these steps:
- The loop calls
iter()on the object following theinkeyword to obtain an iterator. - It enters a
whileloop, repeatedly callingnext()on the iterator. - The loop terminates automatically when a
StopIterationexception is raised, signaling the end of the data.
This process can be manually replicated to understand the underlying logic:
items = ['apple', 'banana', 'cherry']
iterator = iter(items)
while True:
try:
item = next(iterator)
print(f"Processing: {item}")
except StopIteration:
breakException Handling
Exception handling allows a program to intercept and handle runtime errors gracefully rather than crashing. The try-except block is the primary mechanism for this.
- try: Contains the code block that might generate an exception.
- except: Contains the code block that executes if an exception occurs in the try block.
- else: Executes if no exceptions occur in the try block.
- finally: Executes regardless of whether an exception occurred or not, often used for cleanup operations.
def divide(x, y):
try:
result = x / y
except ZeroDivisionError:
print("Error: Division by zero is not allowed.")
else:
print(f"Result is: {result}")
finally:
print("Execution complete.")
divide(10, 2)
# Output: Result is: 5.0
# Output: Execution complete.
divide(10, 0)
# Output: Error: Division by zero is not allowed.
# Output: Execution complete.