Loading...
Loading...
Python interview guide
Comprehensions, generators, decorators, context managers and typing. Every answer is short enough to say aloud, and every question links to the lesson that teaches it.
44 questionsLast updated
Optional[str] and a parameter with a default of None?Optional[str] says the value may be None. A default of None says the argument may be left out. They are separate ideas, and a parameter that defaults to None should be hinted str | None.
A checker refines a wide type inside a branch. After if x is not None or isinstance(x, str), it knows the smaller type in that branch, so the allowed operations change.
Any switches checking off: any operation is allowed. object is the top of the class tree: you can pass anything in, but you may only use what every object supports until you narrow it. Prefer object or a union when you can.
It keeps the relationship between input and output. first(list[int]) is known to return int. With Any the result type is lost and mistakes after the call are not found.
It gives a long type a short, meaningful name, so signatures stay readable. The alias is the same type, not a new one.
Lesson: Optional, Union and Generic Typestuple[int, ...]?When a tuple holds any number of ints. tuple[int, int] means exactly two, so the two forms mean different things.
A class that lists the methods and attributes an object must have. Any class with those members matches it, without inheriting from it. It is the typed form of duck typing, checked by tools such as mypy.
Lesson: Protocols and Structural TypingNominal typing matches by declared names and inheritance: a type fits only if it says so. Structural typing matches by members: a type fits if it has the right methods and attributes. Protocols are structural, ordinary classes and ABCs are nominal.
Lesson: Protocols and Structural TypingWhen the classes come from other code, or when a shared parent is unwanted. A protocol also keeps modules loosely coupled, because the user of the protocol does not import the implementations. Choose an ABC to share code or to get a runtime error for missing methods.
Lesson: Protocols and Structural TypingNo, not by default. Calling a protocol class directly raises an error, and isinstance fails unless the class is marked @runtime_checkable. The real check is done by a type checker before the program runs.
Lesson: Protocols and Structural Typingisinstance only checks that the named members exist. It cannot check signatures or return types, and it is slower than a normal isinstance. Use it for a simple capability test.
Lesson: Protocols and Structural TypingIterable, Sized, Hashable and Callable are protocols. Any object with __iter__ is Iterable, with __len__ is Sized. This is why a function hinted Iterable[int] accepts lists, tuples and generators.
A static checker reads the code and the hints and reports type mismatches without running anything. Tests run the code with chosen inputs. The checker covers every path for type errors, and tests cover behaviour. Teams use both.
Lesson: Checking Code with mypyIt only checks types, and it skips the body of functions without hints by default. Logic errors, wrong values of the right type, and untyped code all pass. Use tests as well, and turn on --strict over time.
It hides a real error and tends to stay forever. Prefer a fix such as narrowing. If you must use it, give the error code, add a short reason, and enable warn_unused_ignores so stale ones are reported.
Lesson: Checking Code with mypyInstall it as a development dependency in the virtual environment, add a [tool.mypy] table to pyproject.toml, and run mypy . or mypy src locally and in continuous integration. Start lenient and tighten the options as hints are added.
The package has no type information that mypy can read. Install a stubs package such as types-requests, or set ignore_missing_imports for that module. Many packages ship their own hints and need nothing.
cast only tells the checker to believe a type, and does nothing at runtime, so a wrong cast hides a bug. isinstance really tests the value and lets the checker narrow the type safely.
Add mypy to the project and start with a lenient configuration. Hint the public functions and the data that crosses module boundaries first, then tighten options such as disallow_untyped_defs per package. Keep tests running, and avoid blanket Any and # type: ignore.
str | None. What must its callers do?Handle the None case before using the value as a string, for example with if value is not None. A checker reports every caller that does not.
Use a protocol when you only need a capability, such as having a pay method, and the classes may come from other code. Use a base class when subclasses share code or you want a runtime error for missing methods.
No. Python ignores them when running. They make development safer, because tools find mistakes early, and they document the code. Some libraries read hints to validate data, but that is separate behaviour.
Lesson: Type Hints CheckpointIt proves the typed code is consistent with its hints. It does not prove the logic is right, it does not check untyped functions by default, and anything marked Any or ignored is outside its view.
Lesson: Type Hints CheckpointA module is a single .py file. A package is a folder of modules, usually with an __init__.py, imported by the folder name. Packages can contain other packages, which gives dotted paths such as shopkit.pricing.
Not since Python 3.3. A folder without it can still be imported as a namespace package. Regular packages keep the file, because it is the place for package setup and a short public API, and many tools expect it.
Lesson: Packages and __init__.pyAbsolute imports read clearly and work in more places, so they are the usual choice. Relative imports are handy inside a package that may be renamed or moved. They only work when the file is imported as part of the package.
Lesson: Packages and __init__.py-m puts the current folder on the path, imports the package properly and runs __main__.py, so relative imports work. Running a file by path treats it as a top-level script with no package.
Older builds ran setup.py, which is code, so tools had to execute it to learn the dependencies. A static TOML file can be read safely by any tool, and one standard file replaces several. PEP 517, 518 and 621 define the format.
The program that turns the source tree into a wheel or an sdist. pip reads [build-system], installs the listed requirements in a temporary environment and calls the backend. Examples are setuptools, hatchling and flit.
No. A library should state ranges, such as requests>=2.30, so that it can live next to other packages. Exact versions belong in a lock file for an application, which records what you tested.
Extras are named groups in [project.optional-dependencies]. A user installs them with square brackets, such as pip install "shopkit[dev]". They suit development tools and optional features.
A hand-written requirements file lists what you want, often as ranges. A lock file is generated and lists every package, direct and indirect, at an exact version, sometimes with hashes. A pip freeze output is a simple lock. Tools such as pip-tools, uv and Poetry write better ones.
Users install your library next to other packages. Exact pins make conflicts likely, because two libraries may need different versions of the same package. A library states the range it works with and lets the application pin.
Lesson: Managing Dependencies with pip and Lock FilesIt gives each project its own set of packages and versions. Two projects can need different versions of the same package without breaking each other, and pip freeze lists only that project's packages.
Change the rules or ask the tool to refresh the lock, install into a clean environment, run the tests and type checker, and review what changed. Commit the lock file with the code change, so the team and the build server use the same versions.
Lesson: Managing Dependencies with pip and Lock FilesAn sdist (source distribution) is an archive of the source that pip must build before installing. A wheel is already built, so pip only unpacks it. Publish both: the wheel for speed, and the sdist for systems with no matching wheel.
Lesson: Building and Publishing a PackageOther projects pin versions and build servers cache them. If a file could change under a version number, the same version would mean different code on different days. A fix therefore needs a new version.
Lesson: Building and Publishing a PackageUse an API token limited to the project, never your account password. Keep it in a keyring or a CI secret, not in files in the repository. Better still, use trusted publishing from the build service, which needs no long-lived token.
Lesson: Building and Publishing a PackageList the wheel and the sdist. Confirm the package files, the version, the dependencies and the licence are right, and that no test data, keys or .env files are included. Then install the wheel in a clean environment and import it.
Move the code into a package folder, ideally under src, add __init__.py, and write a pyproject.toml with [build-system] and [project]. Then install it with pip install -e . in a virtual environment, add tests and a lock file, and build it with python -m build.
A library states ranges in pyproject.toml, so it works with other packages. An application records exact versions in a lock file or requirements.txt, so each install is repeatable.
Version clashes between projects, accidental use of packages installed globally, and incomplete dependency lists, since pip freeze then shows only what this project uses.
Compare the installed versions with the lock file using pip freeze, and check that both use the same Python version. Rebuild a clean environment from the lock file and run the code again.
Pick a free name and a version, check pyproject.toml, run python -m build, list the wheel, install it in a clean environment and import it, then upload to TestPyPI with an API token kept outside the code. Publish to PyPI only after that works.
Each lesson has quizzes, practice and more interview questions on the same topic.
Open the first lesson