Cap each value to a [lo, hi] range. Values below lo become lo, values above hi become hi, and values already in range are unchanged. By hand, apply a three-way branch in a loop. With pandas, Series.clip(lo, hi) performs the same capping in one call.

By hand

For each value, check if v < lo → append lo, elif v > hi → append hi, else → append v unchanged. The trace shows all three branches in action: under-range inputs (3 and 2) hit the first branch, over-range inputs (42 and 28) hit the second, and in-range inputs fall through to else.

naive.py
Replay: real traced execution (multi-file project)
values = [3, 15, 7, 42, 11, 2, 28, 9]
lo = 5
hi = 25
result = []
for v in values:
    if v < lo:
        result.append(lo)
    elif v > hi:
        result.append(hi)
    else:
        result.append(v)
print('RESULT:', result)
  1. values ← [3, 15, 7, 42, 11, 2, 28, 9]

    1values = [3, 15, 7, 42, 11, 2, 28, 9]2lo = 5
    values this step[3, 15, 7, 42, 11, 2, 28, 9]values
  2. lo ← 5

    1values = [3, 15, 7, 42, 11, 2, 28, 9]2lo = 53hi = 25
    values this step5lo
  3. hi ← 25

    2lo = 53hi = 254result = []
    values this step25hi
  4. result ← []

    3hi = 254result = []5for v in values:
    values this step[]result
  5. v ← 3

    4result = []5for v in values:6    if v < lo:
    values this step3v
  6. if v < lo:

    5for v in values:6    if v < lo:7        result.append(lo)
  7. result ← [5]

    6if v < lo:7    result.append(lo)8elif v > hi:
    values this step[] [5]result
  8. v ← 15

    4result = []5for v in values:6    if v < lo:
    values this step3 15v
  9. if v < lo:

    5for v in values:6    if v < lo:7        result.append(lo)
  10. elif v > hi:

    7    result.append(lo)8elif v > hi:9    result.append(hi)
  11. result ← [5, 15]

    10    else:11        result.append(v)12print('RESULT:', result)
    values this step[5] [5, 15]result
  12. v ← 7

    4result = []5for v in values:6    if v < lo:
    values this step15 7v
  13. if v < lo:

    5for v in values:6    if v < lo:7        result.append(lo)
  14. elif v > hi:

    7    result.append(lo)8elif v > hi:9    result.append(hi)
  15. result ← [5, 15, 7]

    10    else:11        result.append(v)12print('RESULT:', result)
    values this step[5, 15] [5, 15, 7]result
  16. v ← 42

    4result = []5for v in values:6    if v < lo:
    values this step7 42v
  17. if v < lo:

    5for v in values:6    if v < lo:7        result.append(lo)
  18. elif v > hi:

    7    result.append(lo)8elif v > hi:9    result.append(hi)
  19. result ← [5, 15, 7, 25]

    8elif v > hi:9    result.append(hi)10else:
    values this step[5, 15, 7] [5, 15, 7, 25]result
  20. v ← 11

    4result = []5for v in values:6    if v < lo:
    values this step42 11v
  21. if v < lo:

    5for v in values:6    if v < lo:7        result.append(lo)
  22. elif v > hi:

    7    result.append(lo)8elif v > hi:9    result.append(hi)
  23. result ← [5, 15, 7, 25, 11]

    10    else:11        result.append(v)12print('RESULT:', result)
    values this step[5, 15, 7, 25] [5, 15, 7, 25, 11]result
  24. v ← 2

    4result = []5for v in values:6    if v < lo:
    values this step11 2v
  25. if v < lo:

    5for v in values:6    if v < lo:7        result.append(lo)
  26. result ← [5, 15, 7, 25, 11, 5]

    6if v < lo:7    result.append(lo)8elif v > hi:
    values this step[5, 15, 7, 25, 11] [5, 15, 7, 25, 11, 5]result
  27. v ← 28

    4result = []5for v in values:6    if v < lo:
    values this step2 28v
  28. if v < lo:

    5for v in values:6    if v < lo:7        result.append(lo)
  29. elif v > hi:

    7    result.append(lo)8elif v > hi:9    result.append(hi)
  30. result ← [5, 15, 7, 25, 11, 5, 25]

    8elif v > hi:9    result.append(hi)10else:
    values this step[5, 15, 7, 25, 11, 5] [5, 15, 7, 25, 11, 5, 25]result
  31. v ← 9

    4result = []5for v in values:6    if v < lo:
    values this step28 9v
  32. if v < lo:

    5for v in values:6    if v < lo:7        result.append(lo)
  33. elif v > hi:

    7    result.append(lo)8elif v > hi:9    result.append(hi)
  34. result ← [5, 15, 7, 25, 11, 5, 25, 9]

    10    else:11        result.append(v)12print('RESULT:', result)
    values this step[5, 15, 7, 25, 11, 5, 25] [5, 15, 7, 25, 11, 5, 25, 9]result
  35. for v in values:

    4result = []5for v in values:6    if v < lo:
  36. stdout ← RESULT: [5, 15, 7, 25, 11, 5, 25, 9]

    11        result.append(v)12print('RESULT:', result)
    values this stepRESULT: [5, 15, 7, 25, 11, 5, 25, 9]stdout

With pandas

Series.clip(lo, hi) caps every element to the given bounds in one pass. The snapshot shows values before and after so the replacements are immediately visible.

library.py
import pandas as pd
from dalib.display import set_display
set_display()

values = [3, 15, 7, 42, 11, 2, 28, 9]
lo = 5
hi = 25
df = pd.DataFrame({'x': values})
clipped = df['x'].clip(lo, hi)
result = clipped.tolist()
print('index:', clipped.index.tolist())
print('dtype:', clipped.dtype)
print('values before:', df['x'].tolist())
print('values after:', clipped.tolist())
print('RESULT:', result)
index: [0, 1, 2, 3, 4, 5, 6, 7]
dtype: int64
values before: [3, 15, 7, 42, 11, 2, 28, 9]
values after: [5, 15, 7, 25, 11, 5, 25, 9]
RESULT: [5, 15, 7, 25, 11, 5, 25, 9]

Implementation notes

  • clip preserves the dtype when all values and bounds are the same numeric type; integer input with integer bounds returns int64.
  • Clipping to a fixed range is sometimes called Winsorizing — replacing extremes with boundary values rather than discarding them.
  • Pass only one bound to clip on one side: s.clip(lower=lo) or s.clip(upper=hi).
  • Cross-reference: where-replace (numpy chapter) for conditional replacement using np.where.