Parse a mixed list of numeric and non-numeric strings, converting invalid entries to None rather than raising. By hand, wrap int(s) in a try/except ValueError and append None on failure. With pandas, pd.to_numeric(errors='coerce') turns every unparseable value into NaN in one call.

By hand

For each string, attempt int(s) inside a try block. If the conversion raises ValueError, catch it and append None instead. The trace shows result growing with integers on valid strings and None on invalid ones.

naive.py
Replay: real traced execution (multi-file project)
strings = ['12', 'x', '7', 'n/a', '28']
result = []
for s in strings:
    try:
        result.append(int(s))
    except ValueError:
        result.append(None)
print('RESULT:', result)
  1. strings ← ['12', 'x', '7', 'n/a', '28']

    1strings = ['12', 'x', '7', 'n/a', '28']2result = []
    values this step['12', 'x', '7', 'n/a', '28']strings
  2. result ← []

    1strings = ['12', 'x', '7', 'n/a', '28']2result = []3for s in strings:
    values this step[]result
  3. s ← '12'

    2result = []3for s in strings:4    try:
    values this step'12's
  4. try:

    3for s in strings:4    try:5        result.append(int(s))
  5. result ← [12]

    4try:5    result.append(int(s))6except ValueError:
    values this step[] [12]result
  6. s ← 'x'

    2result = []3for s in strings:4    try:
    values this step'12' 'x's
  7. try:

    3for s in strings:4    try:5        result.append(int(s))
  8. result.append(int(s))

    4try:5    result.append(int(s))6except ValueError:
  9. except ValueError:

    5    result.append(int(s))6except ValueError:7    result.append(None)
  10. result ← [12, None]

    6    except ValueError:7        result.append(None)8print('RESULT:', result)
    values this step[12] [12, None]result
  11. s ← '7'

    2result = []3for s in strings:4    try:
    values this step'x' '7's
  12. try:

    3for s in strings:4    try:5        result.append(int(s))
  13. result ← [12, None, 7]

    4try:5    result.append(int(s))6except ValueError:
    values this step[12, None] [12, None, 7]result
  14. s ← 'n/a'

    2result = []3for s in strings:4    try:
    values this step'7' 'n/a's
  15. try:

    3for s in strings:4    try:5        result.append(int(s))
  16. result.append(int(s))

    4try:5    result.append(int(s))6except ValueError:
  17. except ValueError:

    5    result.append(int(s))6except ValueError:7    result.append(None)
  18. result ← [12, None, 7, None]

    6    except ValueError:7        result.append(None)8print('RESULT:', result)
    values this step[12, None, 7] [12, None, 7, None]result
  19. s ← '28'

    2result = []3for s in strings:4    try:
    values this step'n/a' '28's
  20. try:

    3for s in strings:4    try:5        result.append(int(s))
  21. result ← [12, None, 7, None, 28]

    4try:5    result.append(int(s))6except ValueError:
    values this step[12, None, 7, None] [12, None, 7, None, 28]result
  22. for s in strings:

    2result = []3for s in strings:4    try:
  23. stdout ← RESULT: [12, None, 7, None, 28]

    7        result.append(None)8print('RESULT:', result)
    values this stepRESULT: [12, None, 7, None, 28]stdout

With pandas

pd.to_numeric(df['x'], errors='coerce') attempts to parse each value; strings that cannot be converted become NaN. The integer values are upcast to float64 to accommodate NaN. The snapshot shows the raw float Series (with nan positions), and result normalises NaN → None with math.isnan for parity with the naive half.

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

strings = ['12', 'x', '7', 'n/a', '28']
df = pd.DataFrame({'x': strings})
s = pd.to_numeric(df['x'], errors='coerce')
result = [int(v) if not math.isnan(v) else None for v in s.tolist()]
print('index:', s.index.tolist())
print('dtype:', s.dtype)
print('values raw:', s.tolist())
print('RESULT:', result)
index: [0, 1, 2, 3, 4]
dtype: float64
values raw: [12.0, nan, 7.0, nan, 28.0]
RESULT: [12, None, 7, None, 28]

Implementation notes

  • errors='coerce' is the key switch: errors='raise' (default) would raise on the first invalid string, same as astype; errors='ignore' returns the original strings for unparseable entries.
  • The float64 upcast is the same NaN-forces-float pattern seen in diff-previous-row and merge-left — integer columns cannot store NaN.
  • Use pd.isna(s) or math.isnan(v) to detect the coerced positions after the call.
  • Cross-reference: cast-numeric-strings (this chapter) for the strict astype approach when all values are guaranteed clean.