Python Module 6
Modules, packages and the standard library interview questions
Interview questions on modules, packages and the standard library: warm-ups, then what each harder question tests and how a good answer starts.
Warm-up questions
Short questions with short answers, each answered in full.
-
Fresher
What is the difference between random.sample() and random.choices()?
Answered in the lesson Random numbers, simulations and statistics
-
Fresher
Why should a Decimal be built from a string rather than from a float?
Answered in the lesson math, decimal and fractions for exact work
-
Fresher
What is the difference between a naive and an aware datetime in Python?
Answered in the lesson Dates, times and time zones (IST included)
-
Fresher
What does if __name__ == "__main__": do, and when does a script need it?
-
Fresher
Why does from . import utils fail when you run the file directly, and how do you run it instead?
Answered in the lesson Packages, __init__.py and relative imports
-
Fresher
What do ==, >= with <, and ~= mean in a requirement such as requests~=2.32?
Answered in the lesson Finding and installing third-party packages
-
Fresher
What is the standard library, and how do you tell whether a module belongs to it?
Answered in the lesson A tour of the Python standard library
Questions with model answers
What each question tests, the first step of a good answer and the follow-ups to expect.
-
Mid to senior
A test suite calls random.seed(1234) once at start-up, and one test compares random.shuffle() of ten user ids with an order stored in the test. Since the suite started running tests in parallel workers, that test fails now and then. Explain why, say what a Python upgrade could do to it, and rewrite the test.
- What it tests
- Shared generator state, what the random module promises across versions, and testing random code by its properties instead of stored outputs.
- First step
- Find every draw between the seed and the shuffle. The module-level functions share one hidden generator, so each test that ran earlier in the same worker moved the stream on, and parallel workers change which tests those are. Then recall what the documentation promises: only random() keeps its stream for a seed across versions.
- Follow-ups
-
- How would you test that the shuffle is fair, without a flaky threshold?
- The random call is deep inside a library you do not own.
- When is a stored seeded output still a reasonable test?
From the lesson Random numbers, simulations and statistics
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.
Passes can’t be bought right now, so the model answers can’t be opened at the moment. If you have a pass, enter your licence key.
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 4 minutes
-
Fresher to mid
A festival sale gives a coupon to 1 order in 50 at random, a store expects 400 orders a day, and the budget covers 14 coupons. Estimate by simulation how likely a day needs 15 or more, to within half a percentage point. How many trials do you run, and how do you know the code is right?
- What it tests
- Sizing a simulation from the standard error, checking it against an exact answer, and reporting an estimate with its uncertainty.
- First step
- Write the error target down first: half a percentage point with about 95 % confidence means two standard errors of at most 0.005, so the number of trials must be at least 4p(1 − p) ÷ 0.005². With p unknown, p = 0.5 is the worst case, 40,000 trials; a short pilot run shows how far below that you can go.
- Follow-ups
-
- The budget rises to 21 and the chance falls to about 0.003 %.
- The simulation is too slow. Speed it up.
- How do you make the result repeatable and still trustworthy?
From the lesson Random numbers, simulations and statistics
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
An invoice service adds GST to each line with floats and round(x, 2), then adds the lines. The finance team's ledger works in decimal, rounds the tax once on each invoice's subtotal with halves going up, and many invoices differ from it by one to three paise. Find both causes and fix the code.
- What it tests
- Binary floats against decimal amounts, half-even against half-up rounding, and how much it matters where the rounding happens.
- First step
- Separate the two causes. Where: rounding each line and adding can differ from rounding the subtotal once, because every rounded line can be off by up to half a paisa. How: round() on a float rounds the stored binary value, half to even, so a product that is exactly 0.225 in decimal can come out as 0.22. Reproduce one invoice under both rules.
- Follow-ups
-
- The ledger rounds per line after all. What changes in your code?
- Amounts arrive from a JSON API as numbers.
- How do you store the amounts in the database?
From the lesson math, decimal and fractions for exact work
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
A coding problem asks for C(n, r) modulo 1,000,000,007 for 200,000 queries with n up to 1,000,000. Returning math.comb(n, r) % MOD for each query passes the small tests and runs out of time on the large ones. Why, and how do you answer every query quickly?
- What it tests
- The cost of big-integer arithmetic, modular inverses with pow(), and precomputing factorial tables within time and memory limits.
- First step
- Estimate the size of the numbers: C(10⁶, 5 × 10⁵) has about 301,000 digits, so each comb() call does big-integer work before % MOD throws almost all of it away. Keep every number below the prime instead: precompute the factorials modulo the prime once, and divide with modular inverses.
- Follow-ups
-
- How do you get all the inverse factorials without a million calls to pow()?
- The modulus is not prime, for example 10⁹.
- Memory is limited to 64 MB.
From the lesson math, decimal and fractions for exact work
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A reminder app stores the next reminder as a UTC datetime and adds timedelta(hours=24) after sending it. London users who chose 09:00 get it at 10:00 from the last Sunday of March; users in India never complain. Explain both, fix the scheduling, and say what to do when a chosen time does not exist.
- What it tests
- Wall-clock rules against elapsed time, daylight-saving transitions, storing zone keys, and local times that are missing or repeated.
- First step
- Separate two kinds of time. Elapsed time, such as "in 24 hours", belongs in UTC, but "every day at 09:00 in London" is a rule on the local clock. In winter 09:00 in London is 09:00 UTC; once the clocks go forward, 09:00 UTC is 10:00 on a London clock. India has no daylight saving time.
- Follow-ups
-
- A user in New York reports the same problem two or three weeks earlier.
- A user chooses 01:30, a time that happens twice in October.
- How do you test this without waiting for March?
From the lesson Dates, times and time zones (IST included)
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Fresher to mid
A shop in India stores the time of every order in UTC. Its daily sales report runs at 00:05 UTC and adds up the orders of the previous UTC day, and its totals never match the shop's till. Which orders land on the wrong day, how much of each day is affected, and how do you fix the query?
- What it tests
- Local business days against UTC days, the +05:30 offset, half-open intervals, and when a daily job may run.
- First step
- Write the shop's day as UTC instants: midnight to midnight in India is 18:30 UTC on the day before to 18:30 UTC. A UTC day therefore starts at 05:30 in India, so the orders placed between midnight and 05:30 Indian time are counted in the previous day's report.
- Follow-ups
-
- The same report now serves shops in Dubai and Singapore.
- Some orders reach the database a few minutes after they are placed.
- Why compare with < the next midnight instead of <= 23:59:59?
From the lesson Dates, times and time zones (IST included)
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
A report script works on your laptop, but on the build server the same commit fails with "AttributeError: module 'statistics' has no attribute 'median'". Nobody changed the script. Explain the likely cause, how you would prove it in a minute, and how you would stop it from happening again.
- What it tests
- The module search order, proving where a module came from, why two environments differ, and preventing shadowing with names, packages and checks.
- First step
- Check which file was imported as statistics. In the job's environment, print statistics.__file__, or read the end of the message: Python 3.13 and newer add a hint that names the file to rename. A path inside the repository means that a file of the project hides the standard module.
- Follow-ups
-
- Why does it work on the laptop but not on the build server?
- Why can a local os.py not hide the real os module in the same way?
- How would you stop the same mistake in the rest of the repository?
From the lesson Modules, imports and __name__
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
In a service package, billing.py and customers.py import each other, and it has worked for months. After someone sorts the imports in main.py, start-up fails with "cannot import name 'Invoice' from partially initialized module 'service.billing'". Explain why, which fixes you would consider, and which one you would choose.
- What it tests
- Module initialisation and sys.modules, why import order matters in a cycle, and choosing between moving code, importing modules instead of names, deferred imports and imports for type checkers.
- First step
- Follow the chain of imports in the traceback to find which module was still running its first lines when the other one asked it for a name. That module is already in sys.modules, but the line that defines the name has not run yet.
- Follow-ups
-
- Why did reordering the imports in main.py, which defines nothing, break it?
- When is an import inside a function acceptable?
- The cycle exists only because of type hints. What then?
From the lesson Modules, imports and __name__
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Mid to senior
Importing one small module of your team's package, mypkg.textutils, takes 1.8 seconds. mypkg/__init__.py imports every submodule so that users can write from mypkg import Report. How do you confirm where the time goes, and how do you make the import fast without breaking that line?
- What it tests
- What runs when a package is imported, measuring with -X importtime, lazy re-exports through a module-level __getattr__, and keeping the public names, type checkers and editors working.
- First step
- Measure first: python -X importtime -c "import mypkg.textutils" prints every module imported, with its own and its cumulative time in microseconds. It will show mypkg/__init__.py importing the heavy submodules, and their dependencies, before textutils even starts.
- Follow-ups
-
- How does a module-level __getattr__ keep from mypkg import Report working?
- How do type checkers and editors still see the lazy names?
- How do you stop the slow import from coming back?
From the lesson Packages, __init__.py and relative imports
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A nightly job is started with python -m shop.orders. Its log shows the start-up line twice, a RuntimeWarning mentions sys.modules, and a counter in shop/orders.py differs between the job and the modules that import it. Explain what is happening and how you would restructure the entry point.
- What it tests
- How -m runs a module as __main__, what happens when the package has imported that module already, why two module objects exist, and entry points in __main__.py or a console script.
- First step
- Read the warning: shop/__init__.py had already imported shop.orders before -m ran the same file again as __main__. One file now backs two module objects, shop.orders and __main__, each with its own globals, so the start-up code ran twice and the counter exists twice.
- Follow-ups
-
- Why does python -m shop, with a __main__.py, not have the problem?
- How would a console script in pyproject.toml change this?
- How do you test that the entry point starts correctly?
From the lesson Packages, __init__.py and relative imports
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
You maintain an internal library used by five services, and also one of those services. A colleague proposes pinning every dependency of both to exact versions in pyproject.toml, to stop surprise upgrades. What do you advise for each, and how do you make the service's builds repeatable?
- What it tests
- Ranges for libraries, complete pins for applications, resolver conflicts, upper bounds, lock files and installs checked by hash.
- First step
- Separate the two roles. The library is installed next to other code, so its pyproject.toml declares the widest ranges it is tested with. The service is the end of the chain, so it records the exact version of every package it installs, direct and indirect, in a lock or requirements file.
- Follow-ups
-
- Should the library put an upper bound such as <3 on its dependencies?
- What do hashes in a requirements file protect against?
- A security fix arrives in a dependency of the library. How does it reach each service?
From the lesson Finding and installing third-party packages
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
On a shared build machine, someone ran pip install reqeusts instead of requests, outside any virtual environment. An hour later the security team reports unusual outbound traffic from that machine. What could the package have done, what do you do now, and what do you change so that a typo cannot run code again?
- What it tests
- That installing and importing both run code, .pth files, the steps after a bad install (isolate, inventory, rotate, rebuild) and controls such as lock files with hashes and an index of approved projects.
- First step
- Treat the machine as compromised and isolate it. A source distribution runs its build code during pip install, and a wheel can add a .pth file that runs at every start of that Python, so the package ran with the user's rights and could read files, environment variables and tokens.
- Follow-ups
-
- Would --only-binary :all: have prevented it?
- Which secrets do you rotate?
- Which checks catch a wrong name before anything is installed?
From the lesson Finding and installing third-party packages
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Mid to senior
A legacy service runs on Python 3.11 and imports cgi, telnetlib and distutils, and its dependencies are years old. You are asked to move it to Python 3.14. How do you find everything that will break, in what order do you fix it, and how do you show that the upgrade is safe?
- What it tests
- Knowing what 3.12 and 3.13 removed, finding the rest with deprecation warnings and tests, choosing replacements, handling old dependencies and rolling out safely.
- First step
- Build the list before changing code. Run the tests on 3.11 and 3.12 with deprecation warnings turned into errors (pytest -W error::DeprecationWarning), because those versions warn about what later versions remove, and search the code and its dependencies for the modules that PEP 594 and PEP 632 removed.
- Follow-ups
-
- Is installing standard-telnetlib from PyPI an acceptable fix?
- A dependency you cannot replace still imports distutils. What are your options?
- How do you stop new code from bringing removed or deprecated modules back?
From the lesson A tour of the Python standard library
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes
-
Fresher to mid
A small service must read a TOML configuration file, parse ISO 8601 timestamps with UTC offsets from an API, make about ten HTTP calls a minute and validate incoming JSON against a JSON Schema. For each job, would you use the standard library or a package from PyPI, and what decides it?
- What it tests
- Knowing what tomllib, datetime, urllib.request and json do and do not do, the running cost of a dependency, and deciding job by job instead of by habit.
- First step
- Check the standard library first, job by job: tomllib reads TOML (3.11 and newer), datetime.fromisoformat() parses ISO 8601 timestamps with offsets, urllib.request makes HTTP calls, and json parses JSON but cannot validate it against a schema. Then add a package only where the gap is real.
- Follow-ups
-
- What does each dependency cost the team over a year?
- When is urllib.request no longer enough?
- How does Python's yearly release cycle affect the choice?
From the lesson A tour of the Python standard library
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 3 minutes