Iterators Generators
An iterator is an object that allows you to cycle Generators are a simple way to create iterators using a
through all the elements of a collection, such as a list function that uses the yield statement. Each time yield
or a tuple. Iterators implement two methods: is called, the generator produces the next value in the
__iter__() and __next__(). sequence.
Example: Example:
# Creating an iterator def my_generator():
my_list = [1, 2, 3, 4] yield 1
my_iter = iter(my_list) yield 2
yield 3
# Using next() to iterate through the list
print(next(my_iter)) # Output: 1 gen = my_generator()
print(next(my_iter)) # Output: 2
print(next(my_iter)) # Output: 3 print(next(gen)) # Output: 1
print(next(my_iter)) # Output: 4 print(next(gen)) # Output: 2
# next(my_iter) # This will raise StopIteration error print(next(gen)) # Output: 3
Advantages: # next(gen) # This will raise StopIteration error
Memory Efficiency: Iterators do not load all elements Advantages:
into memory at once, which makes them suitable for
Memory Efficiency: Like iterators, generators yield
large data sets.
items one at a time, which is memory efficient for
Lazy Evaluation: Elements are computed only when large data sets.
needed, which can improve performance in scenarios
Simpler Syntax: Generators are easier to implement
where not all elements are required.
compared to custom iterators due to the yield
Disadvantages: keyword.
One-time Use: Iterators can only be traversed once. To Disadvantages:
traverse again, you need to create a new iterator.
One-time Use: Generators can only be traversed once.
Complexity: Implementing custom iterators requires To traverse again, you need to create a new generator.
understanding of special methods (__iter__() and
Debugging: Debugging generators can be harder than
__next__()), which can add complexity.
regular functions because the state is maintained
between yield calls.
map lambda
The map function applies a given function to all items A lambda function is a small anonymous function
in an input list (or any other iterable) and returns a defined with the lambda keyword. It can have any
map object (which is an iterator). number of arguments but only one expression.
Example: Example:
# Using map to square each number in the list # Using lambda to create an anonymous function to
double a number
def square(x):
double = lambda x: x * 2
return x * x
print(double(5)) # Output: 10
numbers = [1, 2, 3, 4]
squared_numbers = map(square, numbers)
# Using lambda with map
numbers = [1, 2, 3, 4]
print(list(squared_numbers)) # Output: [1, 4, 9, 16]
doubled_numbers = map(lambda x: x * 2, numbers)
Advantages:
Concise: Allows for concise and readable code.
print(list(doubled_numbers)) # Output: [2, 4, 6, 8]
Performance: Can be more efficient than a for-loop in
some cases, especially for large data sets. Advantages:
Disadvantages: Concise: Provides a compact way to define simple
functions.
Readability: For complex functions, using map can
make the code less readable compared to list Inline Definition: Can be defined inline with the code
comprehensions or loops. that uses it.
Compatibility: The result needs to be explicitly Disadvantages:
converted to a list in Python 3.x for further use.
Readability: Can reduce code readability, especially for
complex expressions.
Debugging: Harder to debug compared to regular
functions due to the lack of a function name.
reduce filter
The reduce function from the functools module The filter function constructs an iterator from
applies a rolling computation to sequential pairs of elements of an iterable for which a function returns
values in a list (or any other iterable). true.
Example: Example:
from functools import reduce # Using filter to get only even numbers from a list
numbers = [1, 2, 3, 4, 5, 6]
# Using reduce to compute the sum of a list even_numbers = filter(lambda x: x % 2 == 0, numbers)
numbers = [1, 2, 3, 4]
sum_of_numbers = reduce(lambda x, y: x + y, print(list(even_numbers)) # Output: [2, 4, 6]
numbers)
Advantages:
Concise: Provides a simple way to filter elements from
print(sum_of_numbers) # Output: 10 a collection.
Advantages: Performance: Can be more efficient than a loop for
large data sets.
Concise: Can perform complex accumulations with a
single line of code. Disadvantages:
Functional Programming: Fits well with a functional Readability: Can be less readable compared to list
programming style. comprehensions for complex filtering conditions.
Disadvantages: Compatibility: The result needs to be explicitly
converted to a list in Python 3.x for further use.
Readability: Can be less readable compared to explicit
loops, especially for complex operations.
Performance: May be slower than a loop in some
cases due to the overhead of function calls.
Decorators: List Comprehensions:
Question: What are decorators in Python and Question: What are list comprehensions and
how are they used? how do they work in Python?
Example Answer: Decorators are a way to Example Answer: List comprehensions
modify or enhance functions or methods provide a concise way to create lists. It
without changing their definition. They are consists of brackets containing an expression
often used for logging, enforcing access followed by a for clause, and then zero or
control, instrumentation, etc. more for or if clauses.
Example: Example:
def my_decorator(func): python
def wrapper(): Copy code
print("Something is happening before the squares = [x**2 for x in range(10)]
function is called.")
print(squares) # Output: [0, 1, 4, 9, 16, 25, 36, 49, 64,
func() 81]
print("Something is happening after the function
is called.")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
Exception Handling: File Handling:
Question: How do you handle exceptions in Question: How do you read and write files in
Python? Python?
Example Answer: Exceptions in Python can be Example Answer: Files can be read and
handled using try, except, else, and finally written in Python using the open function
blocks. along with methods like read, write, readlines,
etc.
Example:
Example:
try:
with open('example.txt', 'w') as file:
result = 10 / 0
file.write("Hello, World!")
except ZeroDivisionError:
print("Cannot divide by zero")
with open('example.txt', 'r') as file:
else:
content = file.read()
print("Division was successful")
print(content) # Output: Hello, World!
finally:
print("This will execute no matter what")