Python and pytest Fundamentals: Fixtures, Decorators, and Generators
CiscoSoftware Engineer · OnsiteLast updated
A three-part Python and pytest fundamentals question covering how fixtures are injected, scoped, torn down, and shared; how decorators work and how to write one that preserves metadata; and how generators produce values lazily. It tests core language mechanics used in test automation.
Answer three fundamentals questions about Python and pytest. Use short code examples wherever they make an explanation concrete.
Clarifying Questions
- Should each answer include working code, or is a precise verbal explanation enough?
- Is the interviewer interested only in the language features, or also in how the team's test framework uses them?
Part 1 — pytest fixtures
What is a pytest fixture, and how does a test get one? Explain fixture scopes, how a fixture cleans up after the tests that use it, and how fixtures are shared across several test files.
What This Part Should Cover
- How pytest finds a fixture and injects its value, including fixtures that depend on other fixtures
- The available scopes, their trade-off between speed and isolation, and the rule for mixing scopes
- Teardown mechanics, and when teardown does or does not run
- Sharing fixtures across files
Part 2 — Decorators
What is a decorator in Python, and what does the @ line above a function do? Write a decorator that logs how long each call to the decorated function takes, and make sure the decorated function keeps its original name and docstring.
What This Part Should Cover
- What the
@syntax is equivalent to, and when the decorator runs - A wrapper that forwards all arguments, returns the result, and still logs when the call raises
- Preserving metadata, and decorators that take their own arguments
Part 3 — Generators
What is a generator in Python? Explain how it differs from a function that builds and returns a list, and when you would choose one. Then write a generator that yields the lines of a large log file that contain a given substring, without reading the whole file into memory.
What This Part Should Cover
- How
yieldsuspends and resumes a function, and the iterator protocol behind it - Memory and latency benefits compared with building a list, and the single-pass limitation
- A streaming file reader that also closes the file correctly
Hints
Hint 1
How the test asks: Think about how a test function receives a fixture's value without importing or calling the fixture.
Hint 2
Setup and cleanup together: Consider which Python construct lets one function run code before a test and then resume after it.
Hint 3
Functions are values: Start from the fact that a function can be passed to another function and returned from one. Then work out what the `@` line does with that.
Hint 4
Check the name: After decorating, print the decorated function's `__name__`. Explain what you see, and why it matters for logs and tooling.
Hint 5
Paused, not finished: Think about what happens to a function's local variables between two values it hands out.
Hint 6
Count the memory: Compare holding every result in memory at once with producing one result at a time, for a file much larger than RAM.
Follow-up questions
- How does `@pytest.mark.parametrize` differ from a fixture declared with `params`?
- Write a decorator that takes arguments, such as `@retry(times=3)`.
- If a consumer stops iterating a generator early, does the code in its `finally` block, or the exit of its `with` block, run, and when?
- A session-scoped fixture opens a database connection, and the suite runs in parallel with pytest-xdist. How many connections are opened, and why?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.