41. Is Python dict order guaranteed
Which statement about iteration order of Python dicts and sets is correct today?
- A.Dicts keep insertion order by spec; sets do not
- B.Both dicts and sets keep insertion order
- C.Neither has a defined order
- D.Dicts are sorted by key; sets by value
Show answer
Answer: A. Dicts keep insertion order by spec; sets do not
Since Python 3.7 the language guarantees that dicts preserve insertion order. Sets make no ordering promise, and string hash randomization can change their order between runs. Use a dict with None values, or sort, when order matters.
42. Set order changing between runs
A Python script prints list(set(names)) and the order differs between runs, breaking a snapshot test. Why?
- A.String hashes are randomized per process
- B.Sets are re-sorted by the garbage collector
- C.Python sets use insertion order but drop it on copy
- D.list() sorts the set randomly
Show answer
Answer: A. String hashes are randomized per process
Python seeds string hashing randomly at startup (PYTHONHASHSEED) to resist hash flooding, so set iteration order for strings changes between runs. Sort the output, or use dict.fromkeys to keep insertion order.
43. Python keys 1, 1.0 and True
What is {1: 'a', 1.0: 'b', True: 'c'} in Python?
- A.{1: 'a', 1.0: 'b', True: 'c'}
- B.{True: 'c'}
- C.{1: 'c'}
- D.{1: 'a'}
Show answer
Answer: C. {1: 'c'}
1 == 1.0 == True and they have the same hash, so they are one key. The first inserted key object, 1, is kept, while each later assignment replaces the value, so the final value is 'c'.
44. Rolling mean at the edges
What does this code print?
import pandas as pd
s = pd.Series([10, 20, 30, 40, 50])
print(s.rolling(3).mean().iloc[[1, 4]].tolist())
- A.[15.0, 40.0]
- B.[nan, 40.0]
- C.[20.0, 40.0]
- D.[nan, 45.0]
Show answer
Answer: B. [nan, 40.0]
rolling(3) needs three values by default (min_periods equals the window), so position 1 has only two and returns NaN. Position 4 averages 30, 40 and 50 to give 40.0. The window is trailing, which is right for features, since it never looks ahead.
45. Reading a global before assigning it
What happens when show() is called?
count = 10
def show():
print(count)
count = 5
show()- A.It prints 10
- B.It prints 5
- C.It raises UnboundLocalError
- D.It prints 10 and changes the global to 5
Show answer
Answer: C. It raises UnboundLocalError
Because count is assigned somewhere inside show, Python treats count as a local variable for the whole function. The print runs before the local has a value, so it raises UnboundLocalError. Declare global count if you really mean the global, or better, pass and return values.
46. A list default in a dataclass
What happens when Python reaches this class definition?
from dataclasses import dataclass
@dataclass
class Cart:
items: list = []- A.Every Cart shares the same items list
- B.Every Cart gets its own empty list
- C.It works, but mypy shows a warning
- D.It raises a ValueError right away
Show answer
Answer: D. It raises a ValueError right away
dataclasses refuse list, dict and set defaults and raise ValueError when the class is defined, because one shared list would leak between instances. The fix is items: list = field(default_factory=list), which calls list() for each new object. This is the dataclass version of the mutable default argument trap.
47. round() on .5 values
What does print(round(2.5), round(3.5)) show?
- A.3 4
- B.2 3
- C.2 4
- D.3 3
Show answer
Answer: C. 2 4
Python's round uses "round half to even", also called banker's rounding: ties go to the nearest even number, so 2.5 becomes 2 and 3.5 becomes 4. This avoids an upward bias when rounding many values. For invoice rounding that must always go half up, use decimal.Decimal with ROUND_HALF_UP.
48. nunique and unique disagree
What are s.nunique() and len(s.unique())?
s = pd.Series([1, 1, np.nan, 2, np.nan])
- A.2 and 2
- B.2 and 3
- C.3 and 3
- D.3 and 2
Show answer
Answer: B. 2 and 3
nunique() skips missing values by default, so it counts only 1 and 2. unique() returns every distinct value including NaN once, giving [1, 2, nan], which has length 3. Use nunique(dropna=False) if NaN should count as its own value.
49. Row count after explode
How many rows does df.explode("tags") return?
df = pd.DataFrame({"id": [1, 2, 3],
"tags": [["a", "b"], ["c"], []]})- A.3
- B.2
- C.4
- D.5
Show answer
Answer: C. 4
explode makes one row per list item, so id 1 gives two rows and id 2 gives one. An empty list does not disappear; it becomes a single row with NaN in tags. That gives 4 rows, and the repeated index labels show which original row each came from.
50. Day-over-day change for many stores
df holds daily sales for many stores, sorted by store then date. df["sales"].pct_change() gives odd values on the first day of each store. Why, and what is the fix?
- A.pct_change needs a DatetimeIndex; set date as the index
- B.The first value is always wrong; drop it with iloc
- C.It needs fill_method=None to stop forward filling
- D.It crosses store boundaries; use groupby("store") first
Show answer
Answer: D. It crosses store boundaries; use groupby("store") first
pct_change compares each row with the row above, ignoring which store it belongs to. At each store boundary, it divides by the previous store's last value. Grouping by store restarts the calculation per store, giving NaN on each store's first day, which is correct.
51. Views and copies in NumPy
What does print(a) show?
a = np.arange(5)
b = a[1:3]
b[0] = 99
c = a[[3, 4]]
c[0] = -1
print(a)
- A.[ 0 1 2 3 4]
- B.[ 0 99 2 -1 4]
- C.[ 0 99 2 3 4]
- D.[ 0 1 2 -1 4]
Show answer
Answer: C. [ 0 99 2 3 4]
Basic slicing returns a view that shares memory with a, so writing to b changes a. Fancy indexing with a list of positions returns a new copy, so writing to c leaves a alone. Call .copy() on a slice when you need independent data.
52. Merging an int key with a text key
orders.cust_id is int64, but customers.cust_id was read as text like "101". What does orders.merge(customers, on="cust_id") do?
- A.It matches the keys by converting both to text
- B.It returns an empty DataFrame
- C.It raises a ValueError about int64 and str columns
- D.It returns all rows with NaN customer columns
Show answer
Answer: C. It raises a ValueError about int64 and str columns
pandas refuses to merge numeric keys with string keys and raises a ValueError telling you the types differ. Fix the types first, for example customers["cust_id"] = customers["cust_id"].astype("int64"), after stripping spaces. Checking df.dtypes before a merge saves a lot of debugging.
53. Different standard deviations for the same data
For x = [2, 4, 4, 4, 5, 5, 7, 9], np.std(x) gives 2.0 but pd.Series(x).std() gives about 2.14. Why?
- A.pandas skips the first value
- B.NumPy divides by n, pandas divides by n - 1
- C.NumPy rounds the result to one decimal
- D.pandas uses the median instead of the mean
Show answer
Answer: B. NumPy divides by n, pandas divides by n - 1
The squared deviations sum to 32. NumPy's default ddof=0 gives the population formula, sqrt(32 / 8) = 2.0, while pandas defaults to ddof=1, the sample formula, sqrt(32 / 7) which is about 2.14. Pass ddof explicitly so results match across tools.
54. groupby().first() mixes rows
Group "a" has rows (p=NaN, q=1) and (p="x", q=2). What does df.groupby("c").first() return for group "a"?
- A.p = NaN and q = 1
- B.p = "x" and q = 2
- C.p = NaN and q = 2
- D.p = "x" and q = 1
Show answer
Answer: D. p = "x" and q = 1
first() returns the first non-missing value of each column separately, so p comes from the second row and q from the first. The output row never existed in the data. Use .head(1) or .nth(0) when you need the actual first row.
55. Dividing by zero in pandas
What does pd.Series([10, 0]) / pd.Series([0, 0]) return?
- A.A ZeroDivisionError
- B.inf and NaN
- C.0 and 0
- D.NaN and NaN
Show answer
Answer: B. inf and NaN
pandas follows floating-point rules: a positive number divided by 0 gives inf, and 0 / 0 gives NaN, with no error. Infinite values then wreck averages and charts. Replace zero denominators first, or clean the result with .replace([np.inf, -np.inf], np.nan).
56. Where NaN goes in a descending sort
A score column holds [70, NaN, 90, 80]. Where does NaN end up after df.sort_values('score', ascending=False)?
- A.First, since NaN counts as the largest
- B.Last, because na_position defaults to 'last'
- C.It is dropped from the result
- D.Between 80 and 70
Show answer
Answer: B. Last, because na_position defaults to 'last'
pandas puts missing values at the end by default whatever the sort direction, because na_position='last'. The result is 90, 80, 70, NaN. Pass na_position='first' to put them at the top, or dropna() before ranking.
57. Times stored as text
An attendance export has times as text like "09:45". =B2-A2 works for some rows but others give #VALUE! because they hold "9.45 am". Which approach is most reliable?
- A.Format the column as Time and retype nothing
- B.Multiply every cell by 24 to convert it into hours first
- C.Use TODAY() to give each time a date
- D.Standardise the text, then convert with TIMEVALUE
Show answer
Answer: D. Standardise the text, then convert with TIMEVALUE
Excel can convert some text times on the fly, but not non-standard ones like "9.45 am". Clean them first, for example SUBSTITUTE the dot with a colon, then use TIMEVALUE to get a real time. Formatting alone never changes text into numbers.
58. Last known value with IGNORE NULLS
In Snowflake, which expression fills each NULL reading with the latest earlier non-NULL reading?
- A.FIRST_VALUE(reading) IGNORE NULLS OVER (ORDER BY ts ROWS UNBOUNDED PRECEDING)
- B.LAG(reading) OVER (ORDER BY ts ROWS UNBOUNDED PRECEDING)
- C.LAST_VALUE(reading) IGNORE NULLS OVER (ORDER BY ts ROWS UNBOUNDED PRECEDING)
- D.LAST_VALUE(reading) OVER (ORDER BY ts ROWS UNBOUNDED PRECEDING)
Show answer
Answer: C. LAST_VALUE(reading) IGNORE NULLS OVER (ORDER BY ts ROWS UNBOUNDED PRECEDING)
With a frame from the start to the current row, LAST_VALUE IGNORE NULLS returns the most recent non-NULL value. FIRST_VALUE IGNORE NULLS returns the very first reading in the series. Without IGNORE NULLS, LAST_VALUE just returns the current row, NULL included.
59. Template lost inside an f-string
A templated sql field is built as below. The query fails because the date filter is wrong. What did the operator actually receive?
table = "sales"
sql = f"SELECT * FROM {table} WHERE dt = '{{ ds }}'"- A.SELECT * FROM sales WHERE dt = '{ ds }'
- B.SELECT * FROM sales WHERE dt = '2026-04-02'
- C.SELECT * FROM {table} WHERE dt = '{{ ds }}'
- D.SELECT * FROM sales WHERE dt = ''
Show answer
Answer: A. SELECT * FROM sales WHERE dt = '{ ds }'
In a Python f-string, {{ and }} are escapes for literal single braces, so the string becomes { ds }, which Jinja does not treat as a template. Write {{{{ ds }}}} inside the f-string, or build the SQL with normal string joining.
60. Sending money amounts in JSON
An API sends "amount": 1999.99 as a JSON number. A tester suggests 199999 in paise, or the string "1999.99". Why?
- A.JSON does not allow decimal numbers at all
- B.Strings are always faster to parse than numbers
- C.Binary floats cannot hold many decimals exactly
- D.Paise values are needed only for GST rules
Show answer
Answer: C. Binary floats cannot hold many decimals exactly
Many JSON parsers turn decimals into binary floats, which can add tiny errors that grow in sums. Integer minor units (paise, fils) or decimal strings keep money exact. Tests should check the type and value match the contract.