Python data types and operators interview questions, with answers
Data types are the first thing a Python interviewer checks, because they decide how every later line behaves. The questions are rarely 'name the types'. They are about the rules underneath: which objects can change, when two names point at the same object, why integer division rounds the way it does, why a decimal like 0.1 misbehaves, and what and and or actually return. Every answer below comes with code you can run, and every output shown was produced by running it.
The questions start with objects and identity, move to numbers, and end with the truth-value rules that decide every if and while. Then take the free Python diagnostic — ten questions across every Python topic in the bank — to see which of these you can explain but not yet predict.
The questions, with answers
1.Which Python data types are mutable, and why does it matter?
In short: Lists, dicts, sets and bytearrays are mutable; numbers, strings, tuples, frozensets and bytes are not — and among the built-in types, only the immutable ones can be dict keys or set members.
A mutable object can change in place after it is created; an immutable one cannot, so every change to it builds a new object. That difference drives three things interviewers probe. Hashing: dict keys and set members must be hashable, and among the built-in types that means immutable, so a tuple can be a key and a list cannot. Shared references: two names bound to one list both see an append, while two names bound to one int never interfere. Defaults: a mutable default argument is shared across calls. The catch shown below is that immutability is shallow: a tuple's items cannot be replaced, but a list inside it can still change.
t = (1, [2, 3]) t[1].append(4) print(t) # (1, [2, 3, 4]) t[0] = 9 # TypeError
2.When should you use is instead of ==?
In short: Use == to compare values and is only to test identity — in practice, comparisons with singletons such as None — because a class can make == return anything.
== calls __eq__ and asks whether two objects are equal; is asks whether two names refer to the very same object, and it cannot be overridden. Two separate lists with the same items are equal but not identical, which is the question this page's sample asks. Style guides insist on x is None rather than x == None because __eq__ is ordinary code: a class can define it to return True for anything, as the one below does, while is None cannot be fooled. Using is to compare numbers or strings is a bug waiting to happen, because whether equal values share one object is an implementation detail, such as CPython's cache of small integers.
class Any: def __eq__(self, o): return True a = Any() print(a == None, a is None) # True False3.How do // and % behave with negative numbers?
In short: // floors toward negative infinity instead of truncating toward zero, and % takes the sign of the divisor, so a == (a // b) * b + a % b always holds.
Python's floor division rounds down, not toward zero, which is where it differs from C and Java, whose integer division truncates. So 7 // 2 is 3 but 7 // -2 is -4, and the remainder follows from the identity a == (a // b) * b + a % b: 7 % -2 is -1, with the sign of the divisor. divmod returns both at once. The practical consequence is that n % k is always in range(k) for a positive k, even when n is negative, which makes it safe for wrapping an index around a circular buffer. The trap is porting arithmetic from a language that truncates; for truncating division, write int(a / b) while the values fit exactly in a float.
print(7 // 2, 7 % 2) # 3 1 print(7 // -2, 7 % -2) # -4 -1 print(divmod(-9, 4)) # (-3, 3)
4.Why is floating-point arithmetic sometimes inexact, and how do you compare floats?
In short: Floats are binary fractions, so most decimals such as 0.1 are stored approximately; compare them with math.isclose, and use decimal.Decimal where exact decimal arithmetic matters.
A float is a 64-bit binary fraction. Numbers like 0.5 are exact, but 0.1 has no finite binary expansion, so the stored value is the nearest representable one, and small errors appear as soon as values are combined, as the first line below shows. This is not a Python bug: every language that uses IEEE 754 doubles behaves the same way. Never test floats for equality with ==. math.isclose compares within a relative tolerance. When money or other decimal quantities must be exact, decimal.Decimal built from strings does true decimal arithmetic, and fractions.Fraction keeps exact ratios.
from math import isclose from decimal import Decimal print(0.1 * 3) # 0.30000000000000004 print(isclose(0.1 * 3, 0.3)) # True print(Decimal("0.1") * 3) # 0.35.Which values are falsy in Python?
In short: None, False, zero of every numeric type, and empty strings, lists, tuples, dicts, sets and ranges are falsy; everything else is truthy unless its class defines __bool__ or __len__.
if x does not compare x with True; it calls bool(x), which uses the object's __bool__ method, or __len__ when there is no __bool__, and treats every other object as true. That is why the string '0' and the list [0] are truthy, as the output below shows: they are non-empty. The idiom if items: is the Pythonic empty check for any container. The trap is a value where zero is legitimate: if count: skips a real count of 0, and if value: cannot tell 0, '' and None apart, so write if value is None: when None is what you mean.
xs = [0, "", None, "0", [0]] print(*map(bool, xs)) # False False False True True
6.What do and and or return in Python?
In short: They short-circuit and return one of their operands, not necessarily a bool: a or b gives a if a is truthy, else b; a and b gives a if a is falsy, else b.
Python evaluates the left operand, decides whether it settles the result, and returns an operand unchanged. That is why name or 'guest' works as a fallback, and why the right side of and is skipped when the left is falsy: the 1 / 0 below is never evaluated. Only not always returns a bool. The fallback idiom has the same trap as truthiness: x or 10 replaces a legitimate 0 or empty string with 10, so when only None should trigger the default, write 10 if x is None else x. Comparisons such as a < b return bools, so combining them with and and or gives a bool as usual.
name = "" or "guest" print(name) # guest print(0 and 1 / 0) # 0 print([] or None) # None
7.How do chained comparisons like a < b < c work?
In short: a < b < c means a < b and b < c, with b evaluated once; every comparison operator chains this way, including == and in, which produces some surprising results.
Python reads a run of comparisons as a conjunction of neighbouring pairs, so 1 < x < 10 checks a range in one expression, and 1 < x > 3 is legal and means 1 < x and x > 3. The middle operand is evaluated only once, which matters when it is a function call. Because in, not in, is and is not are comparison operators too, they chain as well: 0 == 0 in [0] means 0 == 0 and 0 in [0], which is True, while (0 == 0) in [0] asks whether True is in [0], which is False. When an expression mixes different comparison operators, parentheses make the intent explicit.
x = 5 print(1 < x < 10) # True print(1 < x > 3) # True print(0 == 0 in [0]) # True print((0 == 0) in [0]) # False
8.Can Python integers overflow, and what does / return?
In short: Python ints have arbitrary precision and never overflow; / always returns a float, even for exact division, while // returns an int when both operands are ints.
An int grows to whatever size the value needs, limited only by memory, so 2 ** 64 prints exactly instead of overflowing as a 64-bit integer does in Java or C. Arithmetic on very large ints is slower, and converting a huge int to a float can raise OverflowError, because floats do have a limit. True division / always produces a float, so 7 / 7 is 1.0, not 1; use // when an integer result is intended. bool is a subclass of int, so True + True is 2: legal, occasionally useful for counting, and a favourite trick question.
print(2 ** 64) # 18446744073709551616 print(7 / 7, 7 // 7) # 1.0 1 print(True + True) # 2
How the diagnostic asks it
One question from the Python bank, exactly as a sitting would show it. The bank has 3 on data types & operators and 34 across Python.
What does this code print?
a = [1, 2, 3] b = [1, 2, 3] print(a == b, a is b)
- 1True Falsecorrect
- 2True True
- 3False False
- 4False True
a == b compares the lists' contents, which are equal, so it is True. a is b asks whether both names refer to one object; two list literals create two separate lists, so it is False. True True would need b = a. False False treats == as an identity test, and False True is impossible for lists, because an object always equals itself.
Measure it
Reading answers tells you what’s true. A diagnostic tells you what you get wrong.
10 Python questions across its topics, easy to hard, about fifteen minutes. You get a readiness figure with the arithmetic shown, the topics you missed named, and a practice set sized for today. Free: 1 diagnostic a month and 15 problems a day. No card.