Sharpen your backend development skills with this quiz focused on Python decorators, generators, and concurrency. Assess your understanding of core Python interview concepts in a practical, scenario-based format tailored for programmers seeking robust, efficient code.
Which symbol is used in Python to apply a decorator to a function?
Explanation: The @ symbol is placed directly above a function definition to apply a decorator in Python, signaling that the function is being modified or extended. The # symbol is for comments and does not affect function behavior. The & and % symbols are not used for decorators in Python and would result in syntax errors in this context.
What does a Python generator function return when called?
Explanation: Calling a generator function returns a generator object, which can be iterated to yield values one at a time. It does not return a list or tuple, as those require all values to be precomputed and stored. An integer is unrelated to the output of a generator function.
How are multiple decorators applied to a single Python function?
Explanation: Multiple decorators are applied by stacking several @decorator lines above the function definition, each on a separate line. Comma-separating on one line, using square brackets, or chaining after the 'def' keyword are invalid Python syntax for decorators.
Which syntax correctly creates a generator expression that yields squares of numbers from 0 to 4?
Explanation: Generator expressions use parentheses, like (x * x for x in range(5)), to lazily compute values. Square brackets create list comprehensions, not generators. Wrapping the expression in 'list()' evaluates and consumes the generator, while curly braces form a set comprehension.
What is the primary purpose of using the threading module in Python?
Explanation: The threading module allows multiple threads to run concurrently within the same process, improving responsiveness in certain situations. It does not launch code in other languages, cannot optimize code performance on its own, and is not intended for creating data types.
When you decorate a function that accepts arguments, what must the decorator's wrapper function also accept?
Explanation: To ensure the decorator can handle any combination of positional and keyword arguments, the wrapper function inside the decorator should accept *args and **kwargs. Accepting only a single argument, none, or requiring a specific keyword is limiting and breaks compatibility.
What does the built-in function next() do when used on a generator object?
Explanation: The next() function retrieves the next value produced by the generator or raises StopIteration if exhausted. It does not measure the generator's length, terminate it, or reset its state. Generators cannot be reset directly.
If a function is decorated with @dec1 above @dec2, which decorator is applied first?
Explanation: Decorators are applied from the innermost (closest to the function) outward, so @dec2 is wrapped first, then @dec1 wraps that result. Both apply, but not at the same moment nor only the top-most. The order is significant in how they transform the function.
What is the primary difference between using 'yield' and 'return' in a Python function?
Explanation: 'yield' allows functions to produce values one at a time, suspending their state between calls, while 'return' immediately terminates the function and returns a single value. 'yield' does not collect results in a list, nor is it exclusive to decorators.
Which Python module is commonly used for concurrent execution using processes rather than threads?
Explanation: The multiprocessing module provides support for concurrent execution using multiple processes, bypassing some limitations of threading in Python. The threading module is specific to threads, asyncore is used for asynchronous socket handling, and collections is unrelated to concurrency.
Are generator functions in Python stateful across multiple calls to next()?
Explanation: Generators automatically save their state, including local variables and the position after last yield, between calls to next(). They do not restart from the top or require variables to be global or decorated to retain state, as this is the built-in behavior of generator functions.
Which of the following best describes a Python decorator?
Explanation: Decorators are higher-order functions that accept a function and return a new or wrapped version of it. They are not data types, classes, or error-handling keywords. Their main purpose is to add or modify behavior of existing functions.
What is the main use of the concurrent.futures module in Python?
Explanation: concurrent.futures provides high-level interfaces for executing code asynchronously in separate threads or processes through pools. Its purpose is not number generation, date validation, or code compilation, making it focused on concurrent execution.
What exception is raised when a generator is exhausted and next() is called again?
Explanation: When a generator runs out of values, calling next() leads to a StopIteration exception. ValueError, TypeError, and KeyError are not related to generator exhaustion, as they serve different errors in Python.
If you want to record the execution time of a function without altering its code, what Python technique is commonly used?
Explanation: Decorators allow additional behavior, like timing, to be added without modifying the core function code. Rewriting the function is more intrusive, a generator does not provide timing, and while a context manager could time blocks, it's not the standard approach for timing functions.
Which of the following limitations applies to Python's standard threading for CPU-bound tasks?
Explanation: Python's GIL prevents multiple native threads from executing Python bytecode simultaneously in one process, limiting efficiency for CPU-bound work. Threads can perform file I/O, are not always the fastest, and Python's memory management is automatic, not manual.