Skip to content

Numbers & Operators Interview Questions & Answers

16 questions Updated 2026-06-18 Share:

Python interview questions on int/float/complex, floor division and modulo with negatives, arbitrary precision, float precision, bitwise operators, and divmod.

Read the in-depth guidePython Numbers and Operators Explained — int, float, Floor Division, and Floats(opens in new tab)
16 of 16

Three: int (whole numbers, unlimited size), float (double-precision binary floating point), and complex (a real + imaginary part written with j). bool is technically a subclass of int (True == 1).

a = 42          # int
b = 3.14        # float
c = 2 + 3j      # complex
c.real, c.imag  # (2.0, 3.0)
True + True     # 2  — bool is an int subclass

Why it matters: mixing types promotes to the wider one (int + float -> float), and knowing the three types explains conversion and precision behavior.

/ is true division and always returns a float. // is floor division — it rounds toward negative infinity, not toward zero. % is the matching modulo, and in Python its result takes the sign of the divisor.

7 / 2       # 3.5    — always float
7 // 2      # 3
-7 // 2     # -4     — floors toward -infinity, not -3
-7 % 2      # 1      — sign follows the divisor (2)
7 % -2      # -1     — sign follows the divisor (-2)

The identity always holds: (a // b) * b + (a % b) == a. Rule of thumb: Python's floor/modulo differ from C/Java for negatives — expect non-negative % when the divisor is positive.

Python int has arbitrary precision — it grows to hold any value, limited only by available memory. There is no fixed 32/64-bit width, so computations never silently wrap around like in C or Java.

2 ** 100        # 1267650600228229401496703205376
x = 10 ** 1000  # a 1001-digit integer — no overflow
import sys
sys.maxsize     # largest "native" int, but ints can exceed it freely

Why it matters: you can compute huge factorials or cryptographic numbers directly, but very large ints cost more memory and arithmetic gets slower. Rule of thumb: integer overflow is simply not a concern in Python.

Floats are stored in binary (IEEE 754), and values like 0.1 and 0.2 have no exact binary representation — so tiny rounding errors accumulate. This is inherent to binary floating point, not a Python bug.

0.1 + 0.2            # 0.30000000000000004
0.1 + 0.2 == 0.3     # False
round(0.1 + 0.2, 2)  # 0.3   — round for display
import math
math.isclose(0.1 + 0.2, 0.3)   # True — tolerant comparison

from decimal import Decimal
Decimal("0.1") + Decimal("0.2")   # Decimal('0.3')  — exact

Rule of thumb: never compare floats with ==; use math.isclose or round, and reach for Decimal when you need exact decimal arithmetic (e.g. money).

Bitwise operators work on the binary representation of integers: & (and), | (or), ^ (xor), ~ (not/invert), << (left shift), and >> (right shift). Shifting left by n multiplies by 2**n.

5 & 3    # 1   (0b101 & 0b011)
5 | 3    # 7   (0b111)
5 ^ 3    # 6   (0b110)
~5       # -6  (~x == -(x+1))
1 << 4   # 16  (1 * 2**4)
20 >> 2  # 5   (20 // 4)

Why it matters: bitwise ops power flags/bitmasks, fast power-of-two math, and low-level protocols. Rule of thumb: ~x equals -(x + 1) because of two's complement.

divmod(a, b) returns the quotient and remainder as a single tuple (a // b, a % b) in one call. ** is exponentiation; with a third argument, the built-in pow(base, exp, mod) does efficient modular exponentiation.

divmod(17, 5)     # (3, 2)  — quotient and remainder together
2 ** 10           # 1024
pow(2, 10)        # 1024  — same as **
pow(2, 10, 1000)  # 24    — (2**10) % 1000, computed efficiently

Rule of thumb: use divmod when you need both results (e.g. converting seconds to minutes/seconds), and pow(a, b, m) for modular math instead of (a ** b) % m.

bool is a subclass of int, so True behaves as 1 and False as 0 in any numeric context. This lets you sum booleans to count truthy items, but it can also produce surprising results when bools sneak into math.

True + True            # 2
sum([True, False, True])   # 2  — counts the Trues
isinstance(True, int)  # True
["a", "b"][True]       # "b"  — True indexes as 1

Rule of thumb: sum(condition for x in data) is an idiomatic way to count matches, but never rely on bool/int interchange where it harms readability.

int() truncates toward zero (drops the fractional part). round() does banker's rounding (round-half-to-even). float() just widens to a float. They are not interchangeable for negatives or .5 cases.

int(2.9)      # 2    — truncates, no rounding
int(-2.9)     # -2   — toward zero
round(2.5)    # 2    — half to even
round(3.5)    # 4    — half to even
round(2.675, 2)  # 2.67 — float repr bites here

Rule of thumb: int() truncates, round() rounds-half-to-even; for predictable decimal rounding use Decimal.

Python chains comparisons: a < b < c is evaluated as a < b and b < c, with b evaluated once. Each operator is independent, so unusual chains are legal (and sometimes confusing).

1 < 2 < 3        # True  — like (1 < 2) and (2 < 3)
5 < 10 > 3       # True  — legal but unusual
x = 5
0 <= x <= 10     # idiomatic range check

Rule of thumb: use chaining for readable range checks (lo <= x <= hi); avoid mixing operator directions which obscures intent.

For immutable numbers, yes in effect — both rebind x to a new object (ints are immutable, so += cannot mutate in place). The distinction matters for mutable types, but numbers always produce a fresh object.

x = 5
id_before = id(x)
x += 1
id(x) == id_before   # False — new int object

# contrast with a list, where += mutates in place:
lst = [1]; before = id(lst); lst += [2]; id(lst) == before  # True

Rule of thumb: += on numbers/strings/tuples rebinds; on lists/sets/dicts it mutates in place. The operator's meaning depends on the type's __iadd__.

Use math for functions operators don't provide and for correctness on floats: math.sqrt, math.floor/ceil (return ints), math.isnan/isinf, math.gcd, and math.isclose. Note math functions work on floats, not complex numbers.

import math
math.floor(-2.5)   # -3   — returns int, toward -inf
math.ceil(2.1)     # 3
math.gcd(12, 18)   # 6
math.isclose(0.1 + 0.2, 0.3)  # True
math.sqrt(2)       # 1.4142135623730951

Rule of thumb: reach for math for floor/ceil-as-int, gcd, and float-safe checks; use cmath when you need complex-number math.

nan ("not a number") is never equal to anything, including itself. This breaks naive equality and makes containers behave oddly. Use math.isnan() to detect it.

nan = float('nan')
nan == nan          # False
nan != nan          # True  — the canonical nan test
import math
math.isnan(nan)     # True

nan in [nan]        # True! — `in` uses identity-then-equality
sorted([3, nan, 1]) # unreliable order — nan breaks comparisons

Rule of thumb: detect nan with math.isnan, never == float('nan'), and scrub nans before sorting or deduping.

CPython caches small integers from -5 to 256 as singletons, so identical small ints share one object and is happens to return True. This is an implementation detail — never use is to compare numeric values.

a = 256; b = 256
a is b        # True  — cached
a = 257; b = 257
a is b        # False — not cached (in a script/REPL line)
a == b        # True  — always the right test

Rule of thumb: compare numbers with ==. is is for identity (e.g. is None), and small-int caching is not something to rely on.

Write the imaginary part with a j suffix. Complex numbers support arithmetic and have .real, .imag, .conjugate(), and abs() (the magnitude). Use the cmath module for complex-aware math functions.

z = 3 + 4j
z.real, z.imag     # (3.0, 4.0)
abs(z)             # 5.0   — magnitude sqrt(3**2 + 4**2)
z.conjugate()      # (3-4j)
import cmath
cmath.sqrt(-1)     # 1j

Rule of thumb: use abs(z) for magnitude and cmath (not math) for roots/trig on complex values.

Use f-string format specs: , for thousands separators, .2f for fixed decimals, % for percentages, e for scientific, and b/o/x for binary/octal/ hex. The spec mini-language keeps formatting in one place.

n = 1234567.891
f"{n:,.2f}"     # '1,234,567.89'
f"{0.0825:.1%}" # '8.2%'
f"{255:#x}"     # '0xff'
f"{42:08b}"     # '00101010'  — zero-padded binary
f"{n:.2e}"      # '1.23e+06'

Rule of thumb: format specs ({value:,.2f}) handle separators, padding, and bases declaratively — avoid manual string surgery.

Underscores are digit group separators for readability — they're ignored by the parser. They work in int, float, and other-base literals, letting you write large constants clearly.

budget = 1_000_000        # same as 1000000
pi = 3.14_159
flags = 0b_1010_0001      # grouped binary
hex_color = 0xFF_FF_FF

Rule of thumb: use _ to group large literals (millions, byte/nibble boundaries); it has zero effect on the value, only on readability.

More ways to practice

The self-quiz is live. Join our channel for updates, new content & tech tips.

Join our WhatsApp Channel