Challenge your understanding of Python list and dictionary comprehensions as well as iterator and generator mechanics, with an emphasis on performance and lazy evaluation concepts.
List Comprehension Syntax
Which of the following is the correct syntax for a list comprehension that creates a list of squares of the numbers from 0 to 9?
- [x^2 for x in range(10)]
- (x**2 for x in range(10))
- [x**2 for x in range(10)]
- {x**2 for x in range(10)}
- [x*2 for x in range(10)]
Dictionary Comprehension with Filter
How do you construct a dictionary comprehension mapping integer x to x squared for even x in range 5?
- {x: x^2 for x in range(5) if x%2=0}
- {x: x**2 for x in range(5) if x%2==0}
- [x: x**2 for x in range(5) if x%2==0]
- {x: x*x if x%2==0 for x in range(5)}
- (x: x**2 for x in range(5) if x%2==0)
Generator Expression vs. List Comprehension
Which advantage does a generator expression (e.g., (x for x in range(1_000_000))) have over a list comprehension in terms of memory usage?
- It computes items lazily, using significantly less memory at a time
- It stores all items in memory like a list
- It cannot be iterated over multiple times
- It consumes memory proportional to the entire sequence
- It is faster because it precomputes the elements
Iterator Protocol
Which pair of methods must an object implement to act as an iterator in Python?
- __iter__ and __getitem__
- __getitem__ and __len__
- __next__ and __call__
- __next__ and __iter__
- __iter__ and __len__
Comprehension Scope
If a variable 'x' exists outside a list comprehension, what happens if the comprehension also uses 'x' as its loop variable?
- Python raises a syntax error due to scope collision
- Both variables refer to the same memory address
- The outer 'x' is always overwritten
- The meaning of 'x' inside and outside is always linked
- The comprehension's 'x' masks the outer 'x' only inside its own scope in Python 3+
Generator Function Execution
What happens when a generator function is called but no iteration is performed?
- The function returns an empty list
- A TypeError is raised
- All yield expressions are executed immediately
- The function runs to completion
- Nothing in the function body is executed until iteration begins
Comprehensions and Performance
Why are list comprehensions typically faster than equivalent for-loops constructing a list?
- They automatically parallelize iterations
- They use extra CPU cores
- They prevent all variable lookups
- They invoke C-implemented internal functions, reducing Python bytecode execution overhead
- They allocate memory only after building the list
Generator Consumption
If a generator expression is used to sum the cubes of numbers from 0 to 999, which action computes the values?
- Iterating with a for-loop or calling sum(generator)
- Printing the generator variable
- Assigning the generator to a list
- Creating the generator variable
- Calling len() on the generator
Dict Comprehension and Key Collisions
What is the result if a dict comprehension generates duplicate keys?
- A warning is generated but all values are stored
- Duplicates are silently ignored
- Python raises a KeyError
- The dict stores all values for each key as a list
- The last value for a given key overwrites any previous value
Custom Iterators
How is the 'StopIteration' exception used in custom iterator classes?
- It is caught to skip certain elements
- It is raised at the creation of the iterator
- It resumes iteration when caught by __iter__
- It signals the end of iteration when raised by the __next__ method
- It is used to indicate a computation error
List Comprehension Side Effects
Why is it discouraged to use a list comprehension only for its side effects, such as printing or modifying external state?
- List comprehensions always return a dictionary
- They are deprecated in Python 3
- They can be more memory-inefficient than for-loops for side effects
- They support only numeric operations
- Their syntax is reserved for nested loops only
Nested Comprehensions
Which expression generates all ordered pairs (x, y) where x is in [1,2,3] and y is in [4,5] using a list comprehension?
- [(x, y) for y in [4,5] for x in [1,2,3]]
- {(x, y) for x in [1,2,3] for y in [4,5]}
- [(x, y) for x in [1,2,3], y in [4,5]]
- (x, y for x in [1,2,3] for y in [4,5])
- [(x, y) for x in [1,2,3] for y in [4,5]]
Lazy Evaluation
Why do generator expressions support lazy evaluation, and when is this advantageous?
- They evaluate all items before use, ensuring speed for small datasets
- They store data for reuse, increasing performance for repeated access
- They create items only when requested, which is efficient for large or infinite data streams
- They type-check the generated objects at run time
- They automatically parallelize item creation
Iterators and Reusability
What happens if you try to iterate over a generator a second time after it has been exhausted?
- It raises a MemoryError
- The generator raises a ValueError
- A new generator is automatically created
- It restarts from the beginning
- It produces no values because its state is exhausted
Difference Between map and Generator Comprehension
What is one significant difference between using map(f, iterable) and a generator expression (f(x) for x in iterable)?
- Generator expressions evaluate eagerly, but map is lazy
- map returns a map object, while generator comprehensions return a generator object
- map always returns a list in Python 3
- map cannot be used with lambda functions
- Both always result in exactly the same performance