Python interview questions

36 questions across 9 sections, in the order you would learn them. Every answer here is one that works — but an answer you have read is not an answer you can give, so use Test yourself and say it out loud first.

Variables, strings and numbers

Read the section that teaches this

If this comes up in an interview

What is the difference between a list and a tuple?

A list can be changed after creation, a tuple cannot. Because a tuple cannot change, it can be used as a dictionary key and a list cannot. Use a tuple when the group of values is fixed, like a coordinate pair.

Why use join instead of adding strings in a loop?

Strings are immutable, so each + builds a whole new string and copies everything so far. Over many iterations that repeated copying makes the loop much slower. join does it in one pass.

What is the difference between == and is?

== compares values. is compares whether two names point to the same object in memory. Use is only for None, True and False. Using it on numbers or strings seems to work for small values because Python reuses those objects, then fails on larger ones.

What does s[::-1] do?

It reverses the string. The three parts of a slice are start, stop and step, so a step of -1 walks backwards through the whole thing.

Lists, dictionaries and sets

Read the section that teaches this

If this comes up in an interview

How would you remove duplicates from a list?

list(set(items)) is the quickest way, but it loses the original order. If order matters, use list(dict.fromkeys(items)), because dictionaries keep insertion order in modern Python.

Why is checking membership in a set faster than in a list?

A list has to compare against each item in turn, so the time grows with its length. A set uses a hash table, so it jumps straight to where the item would be. That takes the same time regardless of size.

What happens if you use a list as a dictionary key?

It raises a TypeError. Keys must be hashable, which means they cannot change. Lists can change, so they are not hashable. Use a tuple instead.

What is the difference between sorted(x) and x.sort()?

sorted returns a new sorted list and leaves the original alone. .sort() sorts the list in place and returns None. Assigning the result of .sort() to a variable is a common bug, because you get None.

Loops, conditions and functions

Read the section that teaches this

If this comes up in an interview

What is wrong with def f(items=[])?

The default list is created once when the function is defined, not on each call, so every call shares the same list. Values accumulate across calls. Use None as the default and create the list inside the function.

What is the difference between break and continue?

break exits the loop completely. continue skips the rest of the current iteration and moves to the next one.

What does a function return if there is no return statement?

None. This is why assigning the result of a method like list.sort() gives you None, because it changes the list in place and returns nothing.

What is the difference between arguments and parameters?

Parameters are the names in the function definition. Arguments are the actual values you pass when calling it. Interviewers ask this to check you can be precise about terminology.

Errors, files and modules

Read the section that teaches this

If this comes up in an interview

Why should you avoid a bare except?

It catches everything, including KeyboardInterrupt and SystemExit, so the program cannot be stopped normally. It also hides real bugs like typos, turning a crash you would have noticed into silently wrong output.

What is the difference between json.load and json.loads?

load reads from a file object. loads reads from a string. The same distinction applies to dump and dumps.

Why use with when opening a file?

It closes the file automatically when the block ends, even if an exception is raised inside it. Without it, a failure partway through can leave the file open.

When would you create a custom exception class?

When callers need to handle your failure differently from built-in ones. A ModelOutputError can be caught and retried, whereas catching ValueError would also catch unrelated problems.

Type hints and pydantic

Read the section that teaches this

If this comes up in an interview

Are Python type hints enforced at runtime?

No. Python ignores them while running. They exist for editors and type checkers, which is why data from an API still needs real validation with something like pydantic.

What does dict | None mean in a return type?

The function returns either a dictionary or None. A type checker will then warn if you use the result without checking for None first. Older syntax writes it as Optional[dict].

Why use pydantic rather than checking fields by hand?

It gives you validation, type conversion, clear error messages listing every problem, and a JSON schema, all from one class definition. Hand-written checks drift apart from the shape they are meant to enforce.

Where should validation happen in an application?

At the boundary, as soon as untrusted data arrives. After that point everything downstream can assume the data is the right shape, which keeps the checks in one place.

If this comes up in an interview

What is the difference between concurrency and parallelism?

Concurrency means several tasks are in progress and taking turns. Parallelism means they genuinely run at the same instant on different cores. Python's asyncio gives you concurrency on one thread, which is enough when the bottleneck is waiting for the network.

When does async not help?

When the work is CPU-bound. Async overlaps waiting, not computing, and there is still one thread. For heavy computation you need multiprocessing.

What happens if you call a blocking function inside a coroutine?

It stalls the entire event loop, so every other coroutine stops until it returns. The symptom is that concurrent code runs at sequential speed. The fix is an async library or asyncio.to_thread.

How would you call an API 1000 times without being rate limited?

Use asyncio.gather with a Semaphore capping how many are in flight, a timeout on each request, return_exceptions=True so one failure does not lose the rest, and retry with exponential backoff on 429 responses.

Generators and working with large data

Read the section that teaches this

If this comes up in an interview

What is the difference between a list and a generator?

A list computes and stores every item immediately. A generator produces items one at a time on demand and stores only its current position, so memory stays flat no matter how many items there are.

How would you process a file larger than your available RAM?

Loop over the file object rather than calling read or readlines, so it yields one line at a time. Wrap it in a generator if you need to transform the records, and batch it if the next step wants groups.

What happens when you iterate a generator a second time?

You get nothing, and no error. It has been consumed. If you need the values again you must recreate the generator or materialise it into a list.

Can you call len() on a generator?

No. A generator does not know how many items it will produce and cannot look ahead. If you need a count, either convert it to a list or count as you iterate.

If this comes up in an interview

What is the difference between a unit test and an integration test?

A unit test checks one piece in isolation with fast, predictable inputs. An integration test checks that several pieces work together, usually including something real such as a database. You want many of the first and a few of the second.

Why is mocking heavily a problem?

Tests full of mocks assert that your code called your code, which stays true even after you break the behaviour. They also have to be rewritten on every refactor. Fake at the system boundary and let the real logic run.

Is 100% test coverage a good goal?

No. Coverage tells you which lines ran, not whether anything was verified. A suite at 90% that asserts almost nothing is worse than an honest 50%, because it creates confidence that has not been earned.

How do you test code that calls an LLM?

Separate the deterministic parts and test those normally with a fake client returning fixed responses. The quality of the model's output is not a unit test; it needs an eval suite measured over a fixed task set.

Environments, packaging and tooling

Read the section that teaches this

If this comes up in an interview

Why use a virtual environment?

It isolates a project's dependencies. Without one, two projects needing different versions of the same library conflict, and installing globally can break system tools that rely on Python.

What is the difference between requirements.txt and pyproject.toml?

requirements.txt is a flat list of packages to install. pyproject.toml declares the project itself, including metadata, dependencies and tool configuration, and is the modern standard.

How do you handle secrets such as API keys?

Keep them in environment variables, loaded from a .env file that is gitignored, and read at runtime. Never commit them. In production they come from the platform's secret store rather than a file.

How do you read a Python traceback?

Bottom up. The last line names the exception. The frames above show the call path. Find the last frame in your own code, because that is usually where the mistake is.

These are the questions for one topic. The whole question bank covers every topic on the site.