Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Python Module 18

Advanced Python: data model, metaprogramming and internals interview questions

Interview questions on “Advanced Python: data model, metaprogramming and internals”.

22 questions: 4 warm-ups and 18 with model answers · Levels: Fresher to staff

Warm-up questions

Short questions with short answers, each answered in full.

  1. Fresher to mid

    What is the difference between __getattr__ and __getattribute__?

    Answered in the lesson Attribute lookup and the data model

  2. Fresher to mid

    What is the difference between a data descriptor and a non-data descriptor?

    Answered in the lesson Descriptors: how properties and methods work

  3. Fresher to mid

    What is a metaclass in Python, and which one do classes use by default?

    Answered in the lesson Class creation: __init_subclass__ and metaclasses

  4. Fresher

    What is the difference between dir() and vars()?

    Answered in the lesson Introspection: inspect, vars() and type()

Questions with model answers

What each question tests, the first step of a good answer and the follow-ups to expect.

  1. Mid to senior

    A wrapper class forwards attribute reads to self._target from __getattr__. It works everywhere until copy.copy() or pickle.loads() meets it, and both die with RecursionError. Explain the chain of calls, and fix the class so that copies and pickles work.

    What it tests
    How __getattr__ behaves on objects created without __init__, what copy and pickle look up, and writing a fallback that cannot recurse.
    First step
    Ask how copy and pickle build the new object: through __new__, without calling __init__, so it has no _target yet. Then trace the first attribute they read on it, __setstate__, which is missing, so __getattr__ runs and reads self._target, which is missing too.
    Follow-ups

    From the lesson Attribute lookup and the data model

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page.

    Opening the model answers with your pass…

    Model answers open with any MySmartCoPilot pass.

    • Pro pass · 1 week₹79$2.99
    • 30 days₹179$5.99
    • 1 year₹1,699$45

    One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

    It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  2. Mid to senior

    A class has a property area and a __getattr__ that raises "no such field". Production logs show AttributeError: no such field 'area', although area is plainly defined. What is going on, how do you find the real bug, and how do you stop such errors from being hidden?

    What it tests
    Knowing that a property raising AttributeError counts as a failed lookup, debugging around __getattr__, and designing fallbacks that do not swallow real errors.
    First step
    Start from the rule that __getattr__ runs whenever the normal lookup raises AttributeError, and a property's getter raising AttributeError counts. So the getter of area failed inside, perhaps on a misspelt attribute, and __getattr__ replaced that error with its own message about area.
    Follow-ups

    From the lesson Attribute lookup and the data model

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  3. Senior to staff

    Your team wrapped a vendor's payment client in a proxy: __getattr__ forwards every attribute and adds retries to methods named in a list. Months later, with client: fails, isinstance checks against the vendor's class fail, and a new vendor method runs without retries. What went wrong in the design, and what would you build instead?

    What it tests
    Special method lookup, isinstance and proxies, forwarding by name against an explicit interface, and choosing between a proxy, a subclass and an adapter.
    First step
    Separate the three failures by mechanism. with looks up __enter__ and __exit__ on the proxy's class, isinstance checks the proxy's class, and the retries cover only the names in the list. Then ask which operations the business needs from the client, because that list is the real interface.
    Follow-ups

    From the lesson Attribute lookup and the data model

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  4. Fresher to mid

    A validated-field descriptor passes its unit tests, but in production two customers' orders show the same quantity. What is the likely bug, how do you confirm it in a debugger, and where should the descriptor keep each order's value?

    What it tests
    Understanding that one descriptor object serves every instance, debugging with vars(), and choosing per-instance storage that works with the model classes.
    First step
    Recall that the class holds a single descriptor object per field, shared by all instances. Check where __set__ stores the value: if vars(order) is empty while vars(type(order).__dict__['qty']) holds a number, the value lives on the descriptor and every order reads the last one written.
    Follow-ups

    From the lesson Descriptors: how properties and methods work

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  5. Mid to senior

    Twelve model classes have 40 properties between them, and almost all check "a positive number" or "a string of at most N characters". A teammate proposes descriptor classes instead. Make the case for and against, and say what you would do.

    What it tests
    Weighing properties against reusable descriptors: duplication, error messages, readability, performance, tooling and type checking, and knowing the library alternatives.
    First step
    Count the duplication first: 40 getter and setter pairs repeat perhaps five patterns. A descriptor writes each pattern once and learns its field's name from __set_name__, so the comparison is 40 hand-written properties against about five small classes and 40 one-line declarations.
    Follow-ups

    From the lesson Descriptors: how properties and methods work

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  6. Senior to staff

    Design the column attribute of a small ORM so that User.email gives an object you can build queries with, while user.email gives that user's value. Which descriptor methods do you write, what does each receive, and what breaks with __slots__ or with a subclass that redefines the column?

    What it tests
    Using the instance-is-None case of __get__, __set_name__ for column names, per-instance storage and change tracking, and descriptor behaviour under slots and inheritance.
    First step
    Start from the two calls Python makes: User.email calls __get__(None, User) and user.email calls __get__(user, User). Return a query expression in the first case and the stored value in the second, and let __set_name__ record the column's name and owner.
    Follow-ups

    From the lesson Descriptors: how properties and methods work

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  7. Mid to senior

    Plugins register themselves through __init_subclass__. In the test suite the registry holds 14 plugins; in the production service it holds 3, and nothing raised an error. What is happening, and how do you make plugin discovery reliable?

    What it tests
    Knowing that registration happens when a class statement runs, which is when its module is imported, and designing discovery with explicit imports, entry points and checks at start-up.
    First step
    Registration runs when the class statement runs, and that happens when the plugin's module is imported. So compare which modules each process imports: the test suite probably imports every plugin module, while production imports only the three that some other code happens to use.
    Follow-ups

    From the lesson Class creation: __init_subclass__ and metaclasses

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  8. Senior to staff

    A teammate proposes a metaclass that wraps every method of 30 service classes with logging and timing. What questions do you ask, which alternatives do you weigh, and when would you accept the metaclass?

    What it tests
    Judging a metaclass against __init_subclass__, class decorators and explicit decorators on inheritance, conflicts, debugging, performance and signatures.
    First step
    Ask what must be logged, for whom, and at what cost per call, then separate the mechanism from the policy: wrapping methods needs no metaclass, because __init_subclass__ can wrap the methods of each subclass and a decorator can wrap them explicitly.
    Follow-ups

    From the lesson Class creation: __init_subclass__ and metaclasses

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  9. Mid to senior

    Combining your framework's base class with abc.ABC raises "metaclass conflict". Explain the rule behind the error, and give two ways out with their costs.

    What it tests
    How Python picks the most derived metaclass, why unrelated metaclasses conflict, and the costs of a combined metaclass against removing the metaclass.
    First step
    State the rule: a class has exactly one metaclass, and Python picks the candidate that is a subclass of the metaclasses of all the bases. The framework's metaclass and ABCMeta are unrelated, so no candidate qualifies, and the class statement fails before any class is created.
    Follow-ups

    From the lesson Class creation: __init_subclass__ and metaclasses

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  10. Mid to senior

    Your web framework builds request validators from handler signatures with inspect.signature(). After someone adds a timing decorator to every handler, all handlers accept any arguments and validation silently stops. Diagnose the bug, and make the framework robust against it.

    What it tests
    How decorators hide signatures, functools.wraps and __wrapped__, the follow_wrapped option, and failing loudly when a signature cannot be trusted.
    First step
    Print inspect.signature() of one decorated handler: it shows (args, *kwargs), the wrapper's own parameters, because the decorator did not use functools.wraps. Without __wrapped__, signature() has nothing to follow back to the real handler.
    Follow-ups

    From the lesson Introspection: inspect, vars() and type()

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  11. Mid to senior

    A health-check endpoint calls hasattr(client, 'session') on 40 client objects. After a library upgrade its response time jumps from 5 ms to 2 s, and sometimes it raises ConnectionError. Explain what is happening and how you would check for the attribute without side effects.

    What it tests
    Knowing that hasattr() reads the attribute and runs properties, which exceptions it turns into False, and static alternatives such as inspect.getattr_static.
    First step
    hasattr() is getattr() with the result thrown away, so if the upgrade made session a property, every check now runs the property's code, here opening a connection. Confirm it with inspect.getattr_static(client, 'session'), which returns the property object without running it.
    Follow-ups

    From the lesson Introspection: inspect, vars() and type()

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  12. Mid to senior

    A rules feature shows users the source of their rule functions with inspect.getsource(). It works on developers' machines but raises OSError in the deployed app. Give the likely causes and the alternatives you would consider.

    What it tests
    Where getsource() finds source text, why it fails without source files or for code built with exec(), and designing features that do not depend on files being present.
    First step
    Recall where the text comes from: getsource() reads the file named in the function's code object, through linecache, starting at the recorded line. So ask how the app is deployed and how rules are built: only .pyc files, a frozen executable or rules made with exec() leave no readable file.
    Follow-ups

    From the lesson Introspection: inspect, vars() and type()

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  13. Mid to senior

    A service reads its feature flags at start-up with eval() on the text of flags.txt. A teammate says this is safe because the file lives on your own servers. Do you agree? What would you change, and how would you move the existing files over without an outage?

    What it tests
    Treating configuration as data that crosses a trust boundary, choosing literal_eval or a data format over eval, and migrating existing files safely.
    First step
    Ask who can write the file and how it reaches the server: a deploy pipeline, an admin tool, a shared volume. Whoever can change it can run code inside the service with the service's permissions, so today the file is code, not data, and the task is to make it data.
    Follow-ups

    From the lesson The ast module: read code without running it

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 4 minutes
  14. Mid to senior

    A product team wants users to type spreadsheet-style formulas such as price * qty * (1 - discount). An engineer proposes eval(formula, {'__builtins__': {}}, row). Explain why you would not ship that, and design the feature instead.

    What it tests
    Knowing that a restricted eval() is not a sandbox, evaluating an allowlist of node types, resource limits, and error messages that users can act on.
    First step
    Start from the documentation of eval(): overriding the built-ins is not a security mechanism, so no choice of globals makes user text safe to run. The boundary has to be what a formula may contain, and the formula's tree tells you that before anything runs.
    Follow-ups

    From the lesson The ast module: read code without running it

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 4 minutes
  15. Senior to staff

    You must rename a deprecated function, get_rate(), to fetch_rate() across 2,000 files. A teammate writes an ast.NodeTransformer and saves ast.unparse() of each new tree. What goes wrong, and how would you make the change instead?

    What it tests
    What a tree keeps and loses, node positions and their UTF-8 offsets, names that refer to something else, and showing that a large automated change is correct.
    First step
    Run the transformer on one file and compare the output with the original: ast.unparse() writes code from the tree, which holds no comments and no layout, so every line of every file changes, not only the calls. Use the nodes only to find the calls, then edit the original text at their positions.
    Follow-ups

    From the lesson The ast module: read code without running it

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  16. Mid to senior

    After a deploy, a worker still behaves as if reports.py were the old version: a function added in the new version is missing, although the new file is on disk. How do you find which code the worker is running and why, and how do you stop it happening again?

    What it tests
    Using spec.origin and __file__, the order of sys.path, the module cache of a long-running process, and stray copies such as an old installed package.
    First step
    Ask the process itself: log reports.__file__ and reports.__spec__.origin, or call importlib.util.find_spec() in a fresh interpreter started the same way. Either the worker imported another copy earlier on sys.path, or it is an old process whose sys.modules still holds the module it imported before the deploy.
    Follow-ups

    From the lesson Inside the import system

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  17. Mid to senior

    Your team wants pricing rules, written as a Python module, to change in a long-running service without a restart, by calling importlib.reload() when the file changes. What breaks, and what would you build instead?

    What it tests
    Knowing what reload() keeps (from-imports, instances of old classes, module globals), its thread-safety, and designing rule changes as checked data with an atomic switch.
    First step
    List who holds the module's objects: other modules that did from pricing import ..., objects created from its classes, functions passed around as callbacks. reload() rebinds names inside the module only, so all of those keep the old objects while new code runs beside them.
    Follow-ups

    From the lesson Inside the import system

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  18. Mid to senior

    A command-line tool takes 1.8 seconds before it prints --help, and users notice. How do you find which imports cost the time, and what would you change, on Python 3.14 and on 3.15?

    What it tests
    Measuring import cost with -X importtime, telling self time from cumulative time, and the options: moving imports, LazyLoader, lazy imports in 3.15, and work done at import time.
    First step
    Measure before changing anything: run the tool with python -X importtime and sort the modules by cumulative time. The few largest entries, often a heavy library imported at module level for one subcommand, account for most of the 1.8 seconds.
    Follow-ups

    From the lesson Inside the import system

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes

All Python interview questions · The Python track

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.