Python Mid

1 / 55

Is Python a compiled or interpreted language? Explain the role of .pyc files and the Python Virtual Machine (PVM).

Select the correct answer

1

Source is compiled straight to machine code stored in .pyc files for the PVM

2

Source is compiled to bytecode cached in .pyc files, then run by the PVM

3

Source is interpreted line by line and .pyc files hold optimized native binaries

4

Source is linked into an executable while .pyc files store the program's runtime state

What are the major differences between Python 2 and Python 3 that you should be aware of?

Select the correct answer

1

In Python 3 print is a function, strings are Unicode, and / does true division

2

In Python 3 range returns a list, input evaluates code, and tabs are required

3

In Python 3 print is a statement, strings are bytes, and / does floor division

4

In Python 3 xrange replaces range, and integers silently overflow to floats

Explain the LEGB rule. What happens to the scope when you use the global or nonlocal keywords inside a nested function?

Select the correct answer

1

Names resolve Local, Enclosing, Global, Built-in; global rebinds the enclosing scope, nonlocal rebinds module level

2

Names resolve Local, Enclosing, Global, Built-in; global rebinds module scope, nonlocal rebinds the enclosing one

3

Names resolve Built-in, Global, Enclosing, Local; both global and nonlocal create a brand-new local name

4

Names resolve Local, Enclosing, Global, Built-in; global and nonlocal both make the variable read-only everywhere

What happens if you use a mutable object like a list or dictionary as a default argument in a function, and why is this considered a gotcha?

Select the correct answer

1

Each call copies the default, yet the copies all still reference the same underlying buffer in memory.

2

The default is created once at definition time and shared across calls, so mutations persist between invocations.

3

The default is rebuilt on every call, but Python caches the first one and silently reuses it for speed.

4

The interpreter freezes the default as immutable, so any attempt to mutate it raises an error at runtime.

What is a closure in Python, and how does the interpreter 'remember' the values of the enclosing scope even after the outer function has finished executing?

Select the correct answer

1

A nested function captures enclosing variables in cell objects, which keep those references alive after the outer call.

2

A function copies all outer local values into its own namespace, freezing them when the outer function is defined.

3

A decorator stores enclosing variables in a global table, letting the inner function look them up on each call.

4

A nested function reads enclosing variables from the call stack, which Python preserves until the program exits.

Is Python 'call-by-value' or 'call-by-reference'? Explain the concept of 'call-by-object-reference' (or 'assignment').

Select the correct answer

1

Python is call-by-reference, so reassigning any parameter inside a function changes the caller's original variable too.

2

Python passes immutables by value and mutables by reference, choosing the strategy from each argument's type.

3

Python passes object references by value, so rebinding a parameter is local but mutating a shared object is visible.

4

Python is call-by-value, copying every argument fully, so functions can never modify the caller's objects at all.

How do Python's collections.deque and list differ in terms of time complexity for common operations?

Select the correct answer

1

deque offers O(1) random indexing, while list needs O(n) to reach any element by its position.

2

deque gives O(1) appends and pops at both ends, while list is O(1) at the end but O(n) at the front.

3

list provides O(1) front insertion, while deque requires O(n) to append items at either end.

4

Both list and deque provide O(1) appends at both ends, but deque uses O(n) memory to resize.

What requirements must an object meet to be used as a key in a Python dictionary, and how does Python handle hash collisions?

Select the correct answer

1

Keys must be unique objects by identity; collisions are handled by chaining values into nested dictionaries.

2

Keys must be hashable with consistent __hash__ and __eq__; collisions are resolved by probing for open slots.

3

Keys must be immutable strings or numbers only; collisions are stored together in a linked list per bucket.

4

Keys must implement __lt__ for ordering; collisions trigger a full resize and rehash of the entire table.

What is a frozenset, and how does it differ from a regular set?

Select the correct answer

1

An immutable set that is hashable and can be used as a key in a dictionary

2

A mutable set whose elements are automatically kept sorted in ascending order

3

An ordered set that preserves insertion order while rejecting any duplicates

4

A set that stores frozen copies of its objects to block their later mutation

Are Python dictionaries ordered? Explain the insertion-order guarantee introduced in Python 3.7.

Select the correct answer

1

No; ordering is arbitrary, so you must use OrderedDict to retain order

2

No; dicts order keys by hash value, so it depends on the keys that you insert

3

Yes; dicts have always kept their keys sorted alphabetically since early versions

4

Yes; since 3.7 dicts preserve insertion order of keys as a language guarantee

What are defaultdict, Counter, and OrderedDict in the collections module, and when would you use them?

Select the correct answer

1

defaultdict sorts keys, Counter limits duplicate keys, OrderedDict reverses insertion order

2

defaultdict supplies defaults for missing keys, Counter tallies items, OrderedDict tracks order

3

defaultdict locks keys, Counter caps values, OrderedDict sorts keys numerically

4

defaultdict caches lookups, Counter stores unique keys, OrderedDict indexes by position

Explain the 'Easier to Ask for Forgiveness than Permission' (EAFP) coding style. Why is it often preferred in Python over 'Look Before You Leap' (LBYL)?

Select the correct answer

1

Try the operation and handle exceptions if it fails, rather than checking conditions first

2

Check all preconditions with guards before attempting any potentially failing operation

3

Avoid exceptions entirely by returning error codes that the caller must inspect each time

4

Validate inputs at function boundaries so no exception can ever be raised at runtime

Why is it considered bad practice to use except Exception? Explain the Python exception hierarchy and where BaseException fits in.

Select the correct answer

1

It only catches custom errors; BaseException derives from Exception at the bottom

2

It also catches SystemExit and KeyboardInterrupt; both classes are identical

3

It hides bugs by catching unrelated errors; BaseException is the root, Exception sits below

4

It runs slowly at runtime; BaseException is the root but Exception sits above it

What is duck typing, and how does it differ from EAFP?

Select the correct answer

1

Duck typing checks an object's type with isinstance before calling any method on it

2

Duck typing judges an object by the methods it supports rather than its explicit type

3

Duck typing converts objects to one common type automatically before any operation is run

4

Duck typing requires objects to inherit from a shared base class before being used together

How do you define a custom exception, and what are the best practices for exception hierarchies?

Select the correct answer

1

Subclass object and raise it directly, since any class instance can be raised here.

2

Subclass str so the exception carries its message text without any extra attributes.

3

Subclass Exception and group related custom errors under a shared base exception class.

4

Subclass BaseException directly so the errors propagate through all interpreter layers.

What is exception chaining, and what does 'raise ... from ...' do?

Select the correct answer

1

It re-raises the original exception unchanged after running the intervening cleanup code.

2

It sets __cause__ on the new exception, explicitly linking it to the original cause.

3

It suppresses the original traceback entirely so only the new exception is ever displayed.

4

It merges both exceptions into a single object combining their messages and tracebacks.

What are the advantages of using @dataclass over a regular class or a namedtuple, and how does it handle default values and mutability?

Select the correct answer

1

It requires a default factory for every field and forbids inheritance from regular classes.

2

It enforces runtime type checking on all fields and rejects mismatched default values.

3

It produces immutable tuples like namedtuple but with faster attribute access by index.

4

It auto-generates __init__, __repr__, and __eq__ while allowing mutable, typed fields.

How do Python's 'dunder' (magic) methods allow for operator overloading and protocol implementation?

Select the correct answer

1

Python compiles dunder methods into C-level hooks that bypass normal method resolution order.

2

Python dispatches operators and built-in protocols to specially named methods like __add__.

3

Python requires registering each operator with a decorator before the dunder method takes effect.

4

Python overloads operators only for numeric types, ignoring dunder methods on other objects.

What is the relationship between __eq__ and __hash__, and what happens if you override one but not the other?

Select the correct answer

1

Overriding __hash__ without __eq__ sets __eq__ to None, making instances incomparable

2

Overriding __eq__ automatically regenerates a matching __hash__ from the new equality logic

3

Overriding __eq__ without __hash__ sets __hash__ to None, making instances unhashable

4

Overriding either one leaves the other unchanged, so instances stay hashable and comparable

What is the __call__ method, and how does it let you make instances of a class callable?

Select the correct answer

1

Defining __call__ makes instances callable, so instance() invokes instance.__call__()

2

Defining __call__ makes the class callable, so calling it returns a new bound method

3

Defining __call__ overrides __init__ so construction and invocation share logic

4

Defining __call__ lets instances be called only when used as decorators on functions

How does Python determine the truthiness of an object, and what role do __bool__ and __len__ play?

Select the correct answer

1

Python treats every object as truthy unless it defines both __bool__ and __len__

2

Python uses __len__ if defined, else __bool__ (zero is falsy), else the object is falsy

3

Python checks __bool__ and __len__ together, treating an object true only if both agree

4

Python uses __bool__ if defined, else __len__ (zero is falsy), else the object is truthy

What is the purpose of the abc module, and how does it help enforce an interface compared to standard inheritance?

Select the correct answer

1

Provides runtime checking of method arguments through decorators applied to entire classes.

2

Generates concrete default implementations for missing methods so subclasses always work.

3

Registers virtual subclasses but never prevents instantiation of incomplete child classes.

4

Defines abstract base classes that block instantiation until all abstract methods are implemented.

What is the purpose of the typing module? Does Python enforce these types at runtime, and if not, why are they used in modern production codebases?

Select the correct answer

1

Provides type hints; Python ignores them at runtime, but they aid tooling and readability.

2

Provides runtime casting so values are coerced into their annotated types automatically.

3

Provides decorators that validate types only inside functions marked for strict checking.

4

Provides type hints that Python enforces at runtime, raising errors on mismatched arguments.

How does Python's 'Duck Typing' philosophy differ from 'Strong Typing'?

Select the correct answer

1

Duck typing allows implicit conversions; strong typing requires explicit declarations of all types.

2

Duck typing concerns having the right behavior; strong typing concerns not coercing unrelated types.

3

Duck typing checks types at compile time; strong typing defers every check until program runtime.

4

Duck typing forbids inheritance; strong typing relies entirely on class hierarchies for its safety.

Why would you use typing.Annotated?

Select the correct answer

1

To mark a type as deprecated so that static checkers warn whenever the annotation is being used.

2

To attach extra metadata to a type that tools or libraries can read without changing the type.

3

To combine two types into a union that validators check against at the time of a function call.

4

To convert a runtime value into its annotated type by coercing it during each assignment made.

What is the difference between Final and ClassVar in type hinting?

Select the correct answer

1

Final makes an object truly immutable at runtime, while ClassVar enforces the attribute's type while running.

2

Final marks a private attribute name, while ClassVar marks an attribute each instance copies on write.

3

Final marks a name that must not be reassigned, while ClassVar marks an attribute shared at the class level.

4

Final marks an attribute shared at the class level, while ClassVar marks a name that must not be reassigned.

What is 'Duck Typing', and how does it influence the way you design interfaces in Python compared to a strictly typed language like Java?

Select the correct answer

1

An object is automatically cast to its parent type at runtime, encouraging deep inheritance hierarchies over composition.

2

An object's type must be declared up front, encouraging explicit interface inheritance like Java abstract base classes.

3

An object's methods are checked by a compiler before running, encouraging strict static contracts over flexible code.

4

An object's suitability is judged by the methods it supports, encouraging informal protocols over declared interfaces.

What is the difference between an iterable, an iterator, and a generator? What are the memory implications of using a generator over a list comprehension?

Select the correct answer

1

An iterator produces an iterable; a generator produces an iterator; all three load their entire contents into memory at once.

2

An iterable produces an iterator; an iterator yields items via next; a generator is a lazy iterator that saves memory.

3

An iterable yields items via next; an iterator produces an iterable; a generator builds the full list eagerly in memory.

4

An iterable and an iterator are identical; a generator differs only by syntax and stores every item in memory like a list.

How does the yield keyword work, and what is the difference between yield and yield from?

Select the correct answer

1

yield stops the generator permanently, while yield from restarts it from the beginning of the loop

2

yield creates a coroutine object, while yield from converts that coroutine into an awaitable async task

3

yield pauses and returns one value at a time, while yield from delegates iteration to a sub-iterable

4

yield returns all values at once eagerly, while yield from streams them one by one to save memory

What is the difference between an Iterator and an Iterable? How do you implement the Iterator protocol?

Select the correct answer

1

An iterable defines both __next__ and __iter__, while an iterator only needs __getitem__

2

An iterable defines __iter__ returning an iterator; an iterator defines __next__ to yield values

3

An iterator defines __iter__ returning an iterable; an iterable defines __next__ to yield values

4

An iterator defines __len__ and __iter__, while an iterable defines __next__ to produce values

How do decorators work, and how can you ensure the original function's metadata is preserved?

Select the correct answer

1

A decorator subclasses the function object; the __metadata__ attribute restores its original name and docs

2

A decorator wraps a function returning a new one; functools.wraps preserves the original metadata

3

A decorator renames a function in place; functools.wraps copies the wrapper metadata onto its callers

4

A decorator executes a function immediately; functools.cache preserves the original function metadata

How do decorators work under the hood? Explain the concept of a closure and how it allows a decorator to remember the state of the wrapped function.

Select the correct answer

1

A decorator copies the source of the original function and recompiles it with extra behavior injected inline

2

A decorator returns a wrapper closure that captures the original function from the enclosing scope and calls it

3

A decorator stores the wrapped function in a global registry and looks it up by name at every call

4

A decorator mutates the original function object directly so the wrapper closure is never actually needed

Explain how a decorator works conceptually. How would you write a decorator that accepts its own arguments?

Select the correct answer

1

Attach the arguments as attributes on the wrapped function before the decorator returns the wrapper

2

Declare the arguments as global variables so the single decorator function can read them when it runs

3

Pass the arguments directly to the wrapper function and read them from *args at call time only

4

Write an outer factory taking the arguments that returns a decorator, which returns the wrapper function

What are dictionary and set comprehensions, and when would you use them?

Select the correct answer

1

Concise expressions building a sorted dict and an ordered set that always preserve insertion order

2

Concise expressions that build immutable frozen dicts and sets which cannot be modified after creation

3

Concise expressions building a dict of key-value pairs or a set of unique values from an iterable

4

Concise expressions that lazily produce dict and set items one at a time without building them fully

How does functools.lru_cache work, and how does it help with memoization?

Select the correct answer

1

It stores results on disk between runs so the cache survives even after the program fully restarts

2

It precomputes every possible result at import time and stores them in an unbounded lookup dictionary

3

It caches results keyed only by the function name, sharing one stored value across all argument sets

4

It caches results keyed by the call arguments, returning the stored value on repeated calls

What does functools.partial do, and when would you use it?

Select the correct answer

1

It merges two separate functions into one callable that applies both of them to the given arguments

2

It splits a function into smaller callables that each run one statement of the original body in turn

3

It returns a callable that runs only part of a function and defers the remaining lines until later

4

It returns a new callable with some arguments of an existing function already fixed in advance

What is functools.reduce, and how does it differ from a simple loop?

Select the correct answer

1

It applies a two-argument function cumulatively across an iterable to produce a single accumulated result

2

It filters an iterable by a predicate and returns only the items for which the function is true

3

It splits an iterable into chunks and returns a nested list of accumulated partial sums

4

It applies a one-argument function to every element and returns a new lazy iterator of results

What is the itertools module, and what kinds of problems does it help solve?

Select the correct answer

1

A standard library of fast, memory-efficient iterator building blocks for combinatorics and looping

2

A built-in collection of mutable container types that replace lists, sets, and dictionaries

3

A third-party library of vectorized array operations for numerical and statistical data analysis

4

A standard library of functions for parsing, formatting, and converting iterable data structures

What is the walrus operator (:=), and in what situations is it useful?

Select the correct answer

1

It declares a variable as global inside an expression, useful for sharing state across functions

2

It unpacks an iterable into a variable within a statement, useful for splitting function arguments

3

It assigns a value to a variable as part of an expression, useful in comprehensions and while loops

4

It compares two values for identity and binds the result, useful when checking object equality

How do context managers work, and what is the difference between the __enter__/__exit__ and @contextmanager approaches?

Select the correct answer

1

Both require a class; @contextmanager simply renames __enter__ and __exit__ to shorter aliases

2

Both run on entry only; @contextmanager handles cleanup automatically while the methods need explicit calls

3

Both manage setup and teardown; @contextmanager uses a generator with yield instead of two methods

4

Both are async by default; @contextmanager provides synchronous behavior while the methods stay coroutine-based

What is Structural Pattern Matching (match/case) and how does it differ from a standard if/elif/else block?

Select the correct answer

1

It compiles a chain of conditions into a jump table for speed but otherwise behaves like nested branches

2

It evaluates every case in parallel and runs all blocks whose pattern happens to match the subject

3

It compares a value only for strict equality against constants, like a switch statement in other languages

4

It matches a value against structural patterns, destructuring and binding parts rather than just testing booleans

What does it mean that Python's sort is stable, and why does that matter?

Select the correct answer

1

Repeated sorts of the same list always run in identical time complexity

2

Elements comparing equal retain their original relative order after sorting

3

The sort never crashes or raises errors even with mixed-type elements present

4

Sorting always produces the same output regardless of the input order given

What is serialization with the pickle module, and what are its security concerns?

Select the correct answer

1

It compresses objects into bytes and automatically validates their integrity on load

2

It serializes objects to bytes; unpickling untrusted data can run arbitrary code

3

It serializes objects to JSON text and is always safe to load from external sources

4

It encrypts objects into bytes so untrusted sources cannot read or alter the data

What is the Global Interpreter Lock (GIL), and given its existence, how do you write concurrent code that actually runs in parallel across multiple CPU cores?

Select the correct answer

1

Use multiprocessing or C extensions that release the GIL to use multiple cores

2

Use the threading module since each thread runs on a separate CPU core in parallel

3

Increase the number of threads beyond the core count to bypass the GIL limitation

4

Use asyncio coroutines because the event loop schedules tasks across all CPU cores

Are Python threads 'real' native threads?

Select the correct answer

1

Yes, they are OS threads and the GIL lets them run bytecode fully in parallel

2

No, they are cooperative coroutines that yield control only at await points

3

Yes, they are real OS threads, but the GIL prevents parallel bytecode execution

4

No, they are green threads scheduled entirely by the Python interpreter itself

What is the GIL, and why was it originally implemented?

Select the correct answer

1

A queue ordering I/O operations across threads, added to guarantee deterministic execution order.

2

A mutex letting only one thread run Python bytecode at once, added to simplify memory management.

3

A scheduler distributing bytecode evenly across all CPU cores, added to maximize parallel speed.

4

A lock preventing multiple processes from sharing memory, added to improve security isolation.

What is the difference between a thread and a coroutine in the context of the Python runtime?

Select the correct answer

1

Threads suspend only at chosen await points; coroutines can be interrupted at any instruction.

2

Threads are scheduled preemptively by the OS; coroutines are scheduled cooperatively in one thread.

3

Threads always bypass the GIL for true parallelism; coroutines are limited to one core by the GIL.

4

Threads run in separate processes with isolated memory; coroutines share a single global process pool.

Why is multiprocessing often preferred over threading for CPU-bound tasks in CPython?

Select the correct answer

1

Each process has its own interpreter and GIL, so they run Python bytecode in true parallel.

2

Processes are lighter weight than threads, so spawning many of them costs almost nothing.

3

Threads cannot execute C extensions, while processes release the GIL during numeric loops.

4

Processes share memory faster than threads, reducing the copying overhead of CPU-bound work.

Explain the difference between preemptive multitasking (threading) and cooperative multitasking (asyncio). When is asyncio preferred over standard threading?

Select the correct answer

1

Threads share no memory; asyncio shares memory freely, best for parallel number-crunching tasks.

2

Threads run on many cores; asyncio also uses many cores, best for true CPU-bound parallelism.

3

Threads yield only at await points; asyncio preempts anytime, best for heavy CPU computations.

4

The OS switches threads anytime; asyncio yields at await, best for many I/O-bound connections.

How does asyncio achieve concurrency without using multiple threads or processes?

Select the correct answer

1

A single thread interleaves tasks at await points while waiting on non-blocking I/O via the loop.

2

The OS time-slices coroutines across cores, switching whenever a task has run long enough to yield.

3

The interpreter forks lightweight processes per coroutine that communicate through the event loop.

4

A pool of hidden threads runs each coroutine, and the loop merges their results when they finish.

When should you choose asyncio over threading for a high-concurrency task?

Select the correct answer

1

When handling many simultaneous I/O-bound connections that spend most time waiting on the network.

2

When you need true parallel execution of bytecode across threads without being limited by the GIL.

3

When running CPU-heavy computations that must fully utilize every available processor core at once.

4

When each task blocks on long synchronous calls that cannot be rewritten to use non-blocking APIs.

What is the difference between asyncio.gather() and asyncio.wait()?

Select the correct answer

1

gather() only accepts coroutines whereas wait() only accepts created future objects.

2

gather() collects ordered results and propagates errors; wait() returns done and pending sets.

3

gather() runs tasks sequentially while wait() runs every scheduled task concurrently.

4

gather() cancels all tasks on first error while wait() always waits for every task.

What is the difference between a shallow copy and a deep copy, and how does the copy module handle nested objects in each case?

Select the correct answer

1

A shallow copy duplicates every nested object while a deep copy shares them by reference.

2

A deep copy duplicates only the outer object while leaving inner references untouched.

3

A shallow copy duplicates the outer object but shares nested objects by reference.

4

Both copy types fully duplicate nested objects but differ only in execution speed.

How does Python handle circular imports, and what are the common strategies to resolve them?

Select the correct answer

1

Move imports inside functions or restructure modules to avoid partially initialized references.

2

Python automatically merges the two modules into one to silently break the cycle.

3

Duplicate the shared code into both modules since imports between them are impossible.

4

Circular imports always raise an immediate fatal error that cannot be worked around.

Why are strings immutable in Python, and what implications does that have for performance and memory?

Select the correct answer

1

Immutability makes string edits faster in place while increasing total memory usage.

2

Immutability prevents strings from being used as dictionary keys or set members.

3

Immutability allows safe sharing and hashing, but edits create new string objects.

4

Immutability means concatenation modifies the original buffer without new allocations.