skip to content

Core Types and Syntax

What each built-in type really is, when `is` and `==` disagree, and which operations copy versus alias. Interviewers open here because it explains most of Python's famous surprises.

part ofPythonoverview, primer and where to startread it →
on this pageshow

explore

questions

123 · 6 sections

Why use decimal.Decimal instead of float for currency amounts in Python?

level: juniorimportance: must knowfreq 62%
basics
~20 s

A float stores a binary fraction, so an amount written as 0.10 is not held exactly and the tiny errors accumulate as you add. decimal.Decimal stores base-10 digits, so 0.10 built from the string '0.10' is exact and money totals stay exact.

open as a page

Why does 0.1 + 0.2 == 0.3 evaluate to False in Python?

level: juniorimportance: must knowfreq 85%
basics
~20 s

Python's float is IEEE-754 binary64, which stores exactly only fractions with a power-of-two denominator. 0.1, 0.2 and 0.3 each become nearby approximations, and the sum of the first two lands one step above the stored 0.3.

open as a page

Why can a Python int hold 2 ** 200 without overflowing, and what does that cost?

level: juniorimportance: must knowfreq 60%
basics
~20 s

Python 3 has one integer type and it is arbitrary precision: CPython stores a sign plus a variable-length array of digits and grows it on demand, so arithmetic never wraps. You pay in memory and in math that is slower than machine words.

open as a page

What do -7 // 2 and -7 % 2 evaluate to in Python, and why?

level: juniorimportance: must knowfreq 62%
basics
~20 s

-7 // 2 is -4 and -7 % 2 is 1. Python floors the quotient toward negative infinity instead of truncating toward zero, so the remainder always carries the sign of the divisor rather than the dividend.

open as a page

Why does int('3.0') raise ValueError while int(3.0) returns 3?

level: juniorimportance: must knowfreq 70%
basics
~20 s

int() parses text with the integer grammar only, so the dot in '3.0' makes it a ValueError. Given a float object it converts numerically, truncating toward zero. For decimal text, call float() first and then int().

open as a page

What is the difference between Python's str and bytes types?

level: juniorimportance: must knowfreq 85%
basics
~20 s

str holds Unicode code points, meaning text; bytes holds raw octets valued 0 to 255, meaning data. Python 3 never converts between them implicitly: str.encode() produces bytes and bytes.decode() produces text, and each names an encoding.

open as a page

What is the difference between an f-string, str.format and %-formatting in Python?

level: juniorimportance: must knowfreq 80%
basics
~20 s

All three build a str. An f-string is a literal whose expressions are evaluated where it is written, so it cannot be stored as a reusable template; str.format and the % operator format a template string supplied at call time.

open as a page

Why does calling s.upper() on a Python string leave s unchanged?

level: juniorimportance: must knowfreq 72%
basics
~20 s

Python str objects are immutable, so no method can change one in place. str.upper() builds and returns a brand-new string and leaves the original untouched, which is why you must assign the result: s = s.upper().

open as a page

What is the difference between bytes and bytearray in Python?

level: juniorimportance: must knowfreq 62%
basics
~20 s

bytes is an immutable sequence of octets; bytearray is the mutable version you can append to and edit in place. Only bytes is hashable, so only bytes works as a dict key or set member.

open as a page

Why doesn't 'scores.csv'.strip('.csv') simply remove the file extension?

level: juniorimportance: must knowfreq 62%
basics
~10 s

str.strip takes a set of characters, not a suffix. It peels any of '.', 'c', 's' or 'v' off both ends, so 'scores.csv'.strip('.csv') returns 'ore'. Use str.removesuffix('.csv'), added in Python 3.9.

open as a page

Why does `b = a` on a Python list leave both names pointing at one object?

level: juniorimportance: must knowfreq 76%
basics
~20 s

Assignment never copies in Python; it binds a second name to the same object. After b = a both names label one list, so b.append(4) is visible through a. Duplicate explicitly with a.copy(), a[:] or list(a).

open as a page

What is the difference between `is` and `==` in Python?

level: juniorimportance: must knowfreq 88%
basics
~20 s

is asks whether two names are bound to one and the same object, the identity test behind id(). == asks whether the objects compare equal, dispatching to eq. Compare values with ==; reserve is for None, True, False and sentinels.

open as a page

Why does `lst += [4]` change the list other names see, but `n += 1` does not?

level: juniorimportance: must knowfreq 62%
basics
~20 s

+= on a list calls list.__iadd__, which extends that same list object in place, so every name bound to it sees the new items. An int is immutable: n += 1 builds a new int and rebinds only the name n.

open as a page

Which of Python's built-in types are immutable, and which can be changed in place?

level: juniorimportance: must knowfreq 78%
basics
~20 s

int, float, bool, str, bytes, tuple and frozenset are immutable: every apparent change builds a new object. list, dict, set and bytearray are mutable and can be modified in place through any name that refers to them.

open as a page

Why does `dict.copy()` leave nested lists shared with the original dict?

level: middleimportance: must knowfreq 64%
basics
~20 s

dict.copy() is shallow: it builds a new dict whose values are the very same objects as the original's. Replacing a key in the copy is independent, but mutating a nested list is seen by both dicts. copy.deepcopy duplicates the nested objects too.

open as a page

How does a Python range object differ from a list of the same numbers?

level: juniorimportance: must knowfreq 72%
basics
~20 s

A range object stores only start, stop and step, so it occupies the same few dozen bytes whether it spans ten values or a billion. A list of the same numbers materializes every int in memory.

open as a page

Why does `[[0]*3]*3` change a whole column when you assign one cell?

level: juniorimportance: must knowfreq 70%
basics
~10 s

* repeats references, not objects. [[0]*3]*3 stores one inner list three times, so mutating g[0][0] is visible through every row. Build the rows separately with [[0]*3 for _ in range(3)].

open as a page

Why does the Python slice items[1:4] return three elements, not four?

level: juniorimportance: must knowfreq 85%
basics
~20 s

Python slices are half-open: the start index is included and the stop index is excluded. So items[1:4] yields positions 1, 2 and 3, and with the default step the length is simply stop minus start.

open as a page

Why is (5) just an int in Python while (5,) is a one-element tuple?

level: juniorimportance: must knowfreq 74%
basics
~20 s

In Python the comma builds a tuple, not the parentheses. (5) is the integer 5 inside redundant grouping brackets, while the trailing comma in (5,) makes a one-element tuple. Empty () is the only exception.

open as a page

What does `a, b = b, a` do in Python, and why is no temporary variable needed?

level: juniorimportance: must knowfreq 78%
basics
~20 s

Python evaluates the entire right-hand side first, building the pair (b, a), then binds the targets on the left one at a time. Both original values are captured before either name is rebound, so no manual temporary is needed.

open as a page

What does `a < b < c` mean in Python, and how many times is `b` evaluated?

level: juniorimportance: must knowfreq 75%
basics
~10 s

Python expands a < b < c into a < b and b < c, but evaluates the middle expression exactly once. If the first comparison is false, the second comparison is never performed.

open as a page

Why does `3 < 'apple'` raise TypeError in Python 3 when Python 2 ordered them?

level: juniorimportance: must knowfreq 60%
basics
~10 s

Python 3 removed the default ordering between unrelated types. The int's less-than returns NotImplemented for a str, the reflected str greater-than returns NotImplemented too, and with no fallback left the interpreter raises TypeError.

open as a page

In Python, how does `if obj:` decide truthiness for an instance of a custom class?

level: juniorimportance: must knowfreq 58%
basics
~20 s

if obj: calls bool(obj), which looks for __bool__ on the object's type. If there is none, Python falls back to __len__, where a length of 0 means false. With neither defined, every instance is true.

open as a page

Why check `if timeout is None:` instead of `if not timeout:` for an optional argument?

level: juniorimportance: must knowfreq 70%
basics
~20 s

if not timeout: is true for 0, 0.0, '' and [] as well as None, so it silently discards values the caller passed on purpose. is None asks only one question: was the argument omitted?

open as a page

Which built-in Python values are falsy inside an `if` statement?

level: juniorimportance: must knowfreq 85%
basics
~20 s

Falsy built-ins are None, False, zero of any numeric type (0, 0.0, 0j) and every empty container: '', b'', [], (), {}, set(), range(0). Everything else, including the string '0' and the list [0], is truthy.

open as a page

What is the difference between Python's 'utf-8' and 'utf-8-sig' codecs?

level: juniorimportance: must knowfreq 45%
basics
~20 s

Python's utf-8 codec treats a leading byte-order mark as an ordinary character, so it decodes to U+FEFF at the front of the string. The utf-8-sig codec strips one leading mark on read and always writes one on encode.

open as a page

What does the errors= argument to bytes.decode() control in Python?

level: juniorimportance: must knowfreq 70%
basics
~20 s

It chooses what happens when the input bytes are not valid for the codec. 'strict' is the default and raises UnicodeDecodeError; 'ignore' deletes the bad bytes; 'replace' substitutes U+FFFD; 'backslashreplace' writes an escape for each bad byte.

open as a page

What encoding does Python's open() use when you do not pass encoding=?

level: juniorimportance: must knowfreq 60%
basics
~20 s

A text-mode open() with no encoding= uses the locale encoding that locale.getencoding() reports: usually UTF-8 on Linux and macOS, but the ANSI code page on Windows. It is not guaranteed to be UTF-8, so pass encoding= explicitly.

open as a page

Why can two Python strings that look identical compare unequal with ==?

level: middleimportance: must knowfreq 62%
basics
~20 s

Because == compares code points, not shapes. An accented letter can be one precomposed code point or a base letter plus a combining mark; both render the same but differ. unicodedata.normalize('NFC', s) folds them to one form before comparing.

open as a page

Why must a file handed to Python's csv.writer be opened with newline=''?

level: middleimportance: must knowfreq 45%
basics
~20 s

Because csv.writer emits its own '\r\n' terminator. Left at newline=None, text mode translates the '\n' inside it again — on Windows that yields '\r\r\n' and a blank row between every record. newline='' switches that translation off.

open as a page