7 · Comparison & logical operators
Chained comparisons, the `or`-as-default idiom, and `in`/`not in` — the operators that appear in every ML data-validation guard.
`0 <= x <= 1` is valid Python and is evaluated as `(0 <= x) and (x <= 1)` — no C-style `&&` needed.
Without this:
Without chained comparisons and membership tests, range validation and label guards become verbose, error-prone `and` chains that are easy to write wrong.
Python's comparison and logical operators are largely the same as in other languages — with two nice exceptions: chained comparisons and the in/not in membership operators. Together they make guard clauses in data-processing code read almost like English.
Python (in browser)
Each value is evaluated only once — `0 <= f() <= 1` calls `f()` exactly once, not twice.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
The `x or default` idiom is everywhere in Python — but be careful when `x` could legitimately be `0` or another falsy value. Use `x if x is not None else default` in that case.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
`in` on a `set` or `dict` is O(1) — use sets for fast membership tests when your collection is large.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
What does `[] or "fallback"` return?
Chained comparisons shine in if/elif chains — apply them now in the Arena's grade classifier.
- Python's chained comparisons (`0 <= x < 1`) are both more readable and more correct than their C-style equivalent.
- `x or default` gives a fallback when `x` is falsy — but watch out when `0` or `False` are valid values for `x`.
- `in`/`not in` work on strings (substring), lists (linear), sets and dicts (hash — O(1)).
Probability outputs need `if 0 <= prob <= 1` before being passed to a loss function — a single chained comparison catches NaN-like edge cases elegantly. `if label in valid_labels` guards the label encoder before `fit()` so unknown classes don't silently corrupt the mapping. `if model is not None` before `.predict()` is the canonical guard against calling an uninitialized model.
If you remove it: Without `in` guards, an unseen class label reaches `LabelEncoder.transform()` and raises a `ValueError` mid-batch — breaking a training run hours in. Without range guards, probabilities outside `[0, 1]` silently produce negative log-loss values that look like training is improving when the model is actually diverging.