Standard Library
The batteries you reach for daily: re, pathlib and open(), json and csv, datetime with zoneinfo, subprocess, and logging. Interviewers probe which module you pick and the trap each one hides.
part ofPythonoverview, primer and where to startread it →on this pageshowhide
explore
- Text Processing and Regular Expressions20 questions
- re Matching APIs4 questions
- Capture Groups and Substitution4 questions
- Quantifiers, Anchors, and Flags4 questions
- Catastrophic Backtracking Costs4 questions
- Unicode Normalization4 questions
- Files, Paths, and I/O20 questions
- open() Modes and Encodings4 questions
- pathlib and Filesystem Paths4 questions
- Temporary Files and shutil Operations4 questions
- Atomic Writes and Renames4 questions
- Stream Buffering and Flushing4 questions
- Data Formats: JSON, CSV, and Pickle20 questions
- JSON with the json Module4 questions
- Tabular Data with the csv Module4 questions
- pickle and Untrusted Data4 questions
- tomllib and Config Parsing4 questions
- XML with ElementTree4 questions
- Dates, Times, and Time Zones19 questions
- Naive vs Aware datetimes4 questions
- Time Zones with zoneinfo4 questions
- timedelta, Formatting, Timestamps4 questions
- Monotonic vs Wall Clocks3 questions
- DST Folds and Ambiguity4 questions
- OS Interaction, Processes, and CLIs13 questions
- os, sys, and Environment Variables5 questions
- External Commands with subprocess4 questions
- Command-Line Interfaces with argparse4 questions
- Logging16 questions
- Handlers, Formatters, Propagation4 questions
- Levels, Configuration, Anti-Patterns4 questions
- Structured JSON Records4 questions
- Rotation and Queue Handlers4 questions
- Binary Data and Buffers16 questions
- struct Packing and Endianness4 questions
- Base64 and Hex Encoding4 questions
- Compression Codecs and zstd4 questions
- UUID Versions and Bytes4 questions
- Wire-Level Networking12 questions
- Sockets and Blocking I/O4 questions
- selectors and Readiness Loops4 questions
- urllib and http.client4 questions
- Embedded Persistence8 questions
- DB-API Cursors and Transactions4 questions
- sqlite3 in Applications4 questions
- Numbers and Precision12 questions
- Decimal and Fraction Arithmetic4 questions
- Float Comparison and Rounding4 questions
- Reproducible Randomness4 questions
questions
156 · 10 sectionsHow do you name a capture group in a Python re pattern, and what does .groupdict() return?
basics
~10 sWrite (?P<name>...) to name a group. The match object then exposes it as m.group('name'), and m.groupdict() returns a dict mapping every named group to the text it captured; unnamed numbered groups are not included.
Why are regex patterns in Python written as raw strings like r"\d+"?
basics
~10 sA backslash means something to both the string-literal parser and the regex engine. A raw literal stops Python consuming it first, so the engine sees what you typed. Otherwise you must double every backslash.
What is the difference between re.match, re.search and re.fullmatch?
basics
~20 sre.match only tries the pattern at the start of the string, re.search scans forward and returns the first match anywhere, and re.fullmatch requires the pattern to consume the whole string. All three return a Match object or None.
What is the difference between `.*` and `.*?` in a Python `re` pattern?
basics
~20 s.* is greedy: it grabs as much text as it can, then gives characters back only when the rest of the pattern fails. .*? is lazy: it starts empty and grows one character at a time, only when forced.
Why does `re.search(r'(a+)+$', 'a'*30 + '!')` take exponential time?
basics
~20 sThe inner a+ and the outer + can carve the run of as up in about 2^n ways. The trailing ! makes $ fail, so the backtracking engine must try every one of those splits before reporting no match.
What do open()'s 'w', 'a' and 'x' modes each do to an existing file?
basics
~10 s'w' truncates the file to zero bytes, creating it if absent. 'a' leaves the contents alone and writes at the end. 'x' refuses to touch an existing file and raises FileExistsError.
How does pathlib.Path use the / operator to join paths, and what do .name, .stem and .parent return?
basics
~10 spathlib.Path overloads the division operator, so Path("exports") / "schedule.json" builds a new path object with the right separator. On that result .name is "schedule.json", .stem is "schedule", .suffix is ".json" and .parent is Path("exports").
When do you use tempfile.NamedTemporaryFile, TemporaryDirectory or mkstemp?
basics
~10 stempfile.TemporaryDirectory gives a whole scratch directory removed when its with-block ends. tempfile.NamedTemporaryFile gives one auto-deleted open file. tempfile.mkstemp gives a raw file descriptor plus a path you must close and unlink yourself.
How does the write-to-temp-then-os.replace pattern make a file update atomic?
basics
~20 sThe new contents go into a temporary file in the target's own directory; os.replace(tmp, target) then swaps the directory entry in one step, so a reader sees either the whole old file or the whole new one.
Which encoding does open() use in text mode when encoding= is omitted?
basics
~20 sOn Python 3.14 a text-mode open() with no encoding= uses the machine's locale encoding, not UTF-8. The same script can read a file on one machine and raise UnicodeDecodeError on another, so pass encoding= explicitly.
Why is str.split(',') wrong for parsing a CSV line, and what does csv.reader do instead?
basics
~20 sA comma inside a quoted field is data, not a separator, so str.split(',') tears such a row apart. csv.reader runs the quoting state machine over the file object and yields each record as a list of strings.
How do json.load, json.loads, json.dump and json.dumps differ?
basics
~20 sThe trailing s means string. json.loads parses JSON text already in memory and json.load reads it from an open file object; json.dumps returns a JSON string, while json.dump writes that text straight into a file object.
Why does pickle.loads() run arbitrary code when handed untrusted bytes?
basics
~20 sA pickle stream is a small program for a stack machine, not a data document. Its opcodes can import any importable name and call it, so pickle.loads on attacker-controlled bytes runs the attacker's code before you inspect any value.
Why does tomllib.load require a file opened in binary mode ('rb')?
basics
~20 stomllib.load reads bytes and decodes them as UTF-8 itself, because a TOML document is UTF-8 by definition. A file opened in text mode has already been decoded with the platform encoding, so load raises TypeError; open the path with 'rb'.
How do Element.find, findall and iter differ in xml.etree.ElementTree?
basics
~20 sElement.find returns the first match or None, findall returns a list of every match at that path, and iter walks the whole subtree recursively, including the element itself, yielding each element with the given tag.
Why measure elapsed time with time.monotonic() instead of time.time() in Python?
basics
~20 stime.monotonic() only ever moves forward, so the difference between two readings is a true duration. time.time() names a wall-clock instant, and NTP or an operator can step it forwards or backwards, corrupting any elapsed-time calculation.
What makes a Python datetime object aware rather than naive?
basics
~10 sA datetime is aware when it carries a tzinfo whose utcoffset() returns a real offset; otherwise it is naive. datetime.datetime(2026, 9, 5, 12, 0) is naive, and passing tzinfo=datetime.timezone.utc makes the same reading aware.
Why use zoneinfo.ZoneInfo('Europe/Berlin') instead of a fixed UTC+1 offset?
basics
~20 sZoneInfo('Europe/Berlin') carries that region's full IANA rule history, so the offset it reports depends on the moment in question. A datetime.timezone built from a timedelta is one frozen number and is wrong for part of every year.
What does the fold attribute on a datetime.datetime mean during a DST transition?
basics
~20 sfold is a 0-or-1 flag that says which pass through a repeated local wall time you mean: 0 the first occurrence, 1 the second. It defaults to 0 and only changes anything across an offset change.
Why does comparing a naive and an aware Python datetime raise TypeError?
basics
~20 sA naive datetime states no offset, so there is no shared instant to order against an aware one, and Python refuses to guess. Ordering and subtraction raise TypeError; equality does not raise — it quietly returns False.
In argparse, what distinguishes a positional argument from an optional one?
basics
~20 sThe leading dashes decide. add_argument("dataset") defines a positional argument: required, matched by its place on the command line. add_argument("--dataset") defines an optional argument: matched by name, and when absent it takes its default. Both land on the Namespace.
What is the difference between os.environ["DB_URL"] and os.getenv("DB_URL", default)?
basics
~20 sSubscripting os.environ raises KeyError when the variable is unset; os.getenv returns None, or the default you pass. Subscript settings the program cannot run without, so it fails loudly at startup, and use os.getenv only where a default is genuinely correct.
What does subprocess.run() return, and how do you capture the child's output and fail on a non-zero exit?
basics
~20 ssubprocess.run() blocks until the child exits and returns a CompletedProcess carrying args, returncode, stdout and stderr. Pass capture_output=True and text=True to get output as str, and check=True to raise CalledProcessError when the exit code is not zero.
How should a Python CLI report failure — sys.exit codes, and sys.stderr versus sys.stdout?
basics
~20 sExit 0 for success and a small non-zero code for failure via sys.exit, which raises SystemExit. Send results a caller might pipe to sys.stdout, and diagnostics, warnings and errors to sys.stderr so they survive redirection.
In subprocess.run, how is the args parameter interpreted with shell=True versus the default, and what does it cost?
basics
~20 sWith the default shell=False, args is a sequence and each element becomes exactly one argv entry, executed directly with no shell parsing. With shell=True on POSIX, args should be a single string handed to /bin/sh -c, so the shell re-parses it and metacharacters inside interpolated values take effect.
Why use the logging module instead of print() in a Python application?
basics
~20 sEvery logging call carries a severity level, a logger name and a timestamp, and where it goes is decided once at startup rather than at the call site. print() writes an unconditional bare line to stdout with none of that.
How do logging.handlers.RotatingFileHandler and TimedRotatingFileHandler differ?
basics
~20 sBoth write to one file and roll it aside, but RotatingFileHandler rolls over when the file would exceed maxBytes, while TimedRotatingFileHandler rolls over on a clock boundary chosen by when and interval. Each keeps backupCount old files.
Why call logging.getLogger(__name__) in each module instead of logging.info() directly?
basics
~20 slogging.getLogger(name) returns a logger named after the module's import path, so every record says where it came from and configuration can be aimed at one package. Calling logging.info goes through the root logger, which loses that origin.
Why does a logging.Logger set to DEBUG still produce no DEBUG output?
basics
~20 sLevels filter twice. The logger's own effective level decides whether a record is created at all, and then every handler applies its own level before emitting. A handler left at WARNING silences DEBUG no matter what the logger says.
What does logging's extra= dict add to a LogRecord, and when does it raise KeyError?
basics
~20 sEach key in the extra mapping becomes an attribute on the LogRecord itself, so a formatter can emit it as a field. Logger.makeRecord raises KeyError if a key collides with an existing record attribute or with message or asctime.
Why does base64.b64encode reject a str, and what do you write instead?
basics
~10 sbase64.b64encode is a bytes-to-bytes function: it needs a bytes-like object and returns bytes. Encode text first with str.encode('utf-8'), then call .decode('ascii') on the result to get a str for JSON.
How do struct.pack and struct.unpack convert Python values to and from bytes?
basics
~20 sstruct.pack takes a format string plus values and returns a bytes object laid out exactly as that format describes. struct.unpack reverses it and always returns a tuple, even when the format has a single field.
How do Python's uuid.uuid4, uuid.uuid1 and uuid.uuid5 differ in where their bits come from?
basics
~20 suuid.uuid4 fills 122 bits from the operating system's random source. uuid.uuid1 encodes a timestamp plus the host's 48-bit node address. uuid.uuid5 hashes a namespace UUID together with a name, so the same name always produces the same UUID.
Why can zlib.compress exhaust memory on a multi-gigabyte file, and what replaces it?
basics
~10 szlib.compress takes one bytes object and returns another, so both the whole input and the whole output sit in memory at once. Stream instead: zlib.compressobj(), feed it chunks with compress(), and finish with flush().
Why does struct.calcsize('@ci') exceed struct.calcsize('<ci')?
basics
~20 sThe '@' prefix means native byte order with native alignment, so struct inserts pad bytes before the int — typically eight bytes in total. The '<' prefix selects little-endian standard sizes with no alignment padding, giving exactly five.
Which socket.socket calls set up a listening TCP server, and what does the client call?
basics
~20 sThe server creates a socket, binds it to a local address, calls listen, then blocks in accept, which returns a new socket for one client; only that socket carries data. The client creates its own socket and calls connect.
Why does selectors.EVENT_WRITE fire on nearly every loop pass, and when should you register for it?
basics
~20 sA socket is writable whenever its kernel send buffer has room, which is almost always. Register selectors.EVENT_WRITE only while unsent bytes are actually queued for that socket; otherwise select() returns instantly every pass and the loop spins at full CPU.
Why can socket.socket.recv return only part of the message the peer sent, and what fixes it?
basics
~20 sTCP is a byte stream with no message boundaries, so recv returns whatever has arrived, up to the size you asked for. Frame messages yourself with a length prefix or a delimiter, and loop until one message is complete.
What is the difference between urllib.error.HTTPError and urllib.error.URLError?
basics
~20 sHTTPError means the server answered with a status urllib treats as an error; URLError means no HTTP answer arrived at all, such as a name-resolution or connection failure. HTTPError is a subclass of URLError, so catch it first.
What does selectors.DefaultSelector let one thread do that a blocking socket.recv() cannot?
basics
~20 sIt asks the kernel which of many registered sockets are ready right now, so one thread can serve thousands of connections. A blocking socket.recv() parks that thread on one connection until that single connection has data.
In Python's DB-API, how do cursor fetchone(), fetchmany() and fetchall() differ?
basics
~20 sAll three read from one cursor's open result set and advance the same position. fetchone() returns the next row or None when exhausted, fetchmany(n) returns up to n rows in a list, and fetchall() returns every remaining row.
In Python's sqlite3, why pass values as ? placeholders instead of building the SQL with an f-string?
basics
~20 ssqlite3 compiles the statement once and binds each Python value as a typed parameter, so no quoting or escaping ever happens. An f-string splices the value into the statement text, where it can change what the SQL means.
Why do a DB-API connection's uncommitted writes vanish when you close it?
basics
~20 sPEP 249 connections are transactional by default and open a transaction implicitly, with no BEGIN call in the API. Only commit() makes the work durable; close() without it performs an implicit rollback, so the writes are discarded.
What does Python's sqlite3 do about transactions by default, and how does the autocommit attribute change it?
basics
~20 sBy default sqlite3 opens a transaction implicitly before an INSERT, UPDATE, DELETE or REPLACE and leaves it open until you call Connection.commit; nothing else commits for you. Setting Connection.autocommit to True or False replaces that legacy behaviour with explicit modes.
What does a DB-API driver's paramstyle attribute declare, and why does it hurt portability?
basics
~20 sPEP 249 makes every driver module expose a paramstyle string naming the placeholder syntax it accepts: qmark, numeric, named, format or pyformat. Because the driver fixes the style, statements written for one driver do not run on another.
Why should a decimal.Decimal be built from a string rather than from a float?
basics
~10 sDecimal(0.1) converts the float exactly, so it stores 0.1000000000000000055511151231257827..., the binary approximation the float already was. Decimal("0.1") parses the decimal digits you actually wrote and stores exactly one tenth.
What does calling random.seed(42) do to the sequence returned by random.random()?
basics
~20 sIt resets the internal state of the one Mersenne Twister generator that backs the random module's functions. Any run that seeds with the same value then replays the identical sequence of numbers in the same order.
How does decimal.Decimal.quantize round a money amount, and what rounding does it use by default?
basics
~10 squantize takes a pattern Decimal such as Decimal("0.01") and returns a value with that same exponent, rounding the extra digits away. The rounding rule comes from the current decimal context, whose default is ROUND_HALF_EVEN.
How do you choose between statistics.mean, median, stdev and pstdev in Python?
basics
~20 sstatistics.mean averages every value, so one outlier drags it; statistics.median returns the middle value and ignores how extreme the tail is. statistics.stdev divides by n-1 for a sample, statistics.pstdev by n for a whole population.
When does math.fsum give a different total than the built-in sum() over the same floats?
basics
~20 smath.fsum tracks exact partial sums and rounds once at the end, so its total is always correctly rounded. The built-in sum() has compensated since Python 3.12, but its single correction term can still drift across widely separated magnitudes.