← Home

013. Type Conversion

Explicit conversion is safer than implicit coercion

013. Type Conversion

Aryan’s RAM monitor reads its config from a file like this:

warn_threshold_mb = 512
kill_enabled = true
check_interval_sec = 0.5

Every value arrives as a string. Python’s file I/O doesn’t know that 512 is a number — it just sees the characters “5”, “1”, “2”.

Aryan must explicitly convert:

  • "512"int(...) for the threshold
  • "0.5"float(...) for the interval
  • "true"bool — but NOT bool("false")!

The classic trap: bool("false") returns True because any non-empty string is truthy. He must compare the string to “true” instead.

The broken code does the int and float conversions but gets the boolean wrong — it uses bool() directly, so both “true” and “false” return True.


💡 Fun fact: Python’s explicit conversion philosophy (“Explicit is better than implicit”) is encoded in PEP 20 — The Zen of Python. Unlike JavaScript, which silently coerces "5" + 3 to "53", Python raises a TypeError. This strictness was a deliberate choice to make bugs visible rather than hidden.

⚠️ Watch out: bool("false") returns True — because any non-empty string is truthy in Python. bool() tests emptiness, not string content. This trips up nearly every beginner reading config files; always compare the string directly: active_str.lower() == "true".

🤔 Think about it: Python’s int("3.14") raises a ValueError, but int(float("3.14")) works. Why does int() refuse to parse a decimal string directly, and what does that tell you about Python’s approach to type conversion safety?

Learning objectives

  • Convert strings to int and float with int() and float()
  • Understand why bool() fails for “true”/“false” strings
  • Convert string booleans correctly using string comparison

Key concepts

  • type conversion
  • int()
  • float()
  • bool()

Try it

Concept detail

Type conversion (casting) explicitly changes a value from one type to another. Python’s built-in converters: int(), float(), str(), bool(), list(), tuple(), set().

Common patterns: int(“42”) → 42 float(“3.14”) → 3.14 str(100) → “100” int(“3.14”) → ValueError — use float() first, then int()

The classic trap — bool() on strings: bool(“true”) → True (non-empty string) bool(“false”) → True (non-empty string!) bool(“0”) → True (non-empty string!) bool(“”) → False (empty string)

bool() checks if the argument is “truthy” (non-empty, non-zero, non-None). It does NOT parse string content. “false” is a 5-character string, so it’s truthy.

The correct way to convert “true”/“false” strings: active_str.strip().lower() == “true”

This compares the normalised string content and returns a real Python bool. .strip() handles accidental whitespace, .lower() handles mixed case.

Explicit is better than implicit: Python won’t silently coerce types the way JavaScript does. That’s a feature — it forces you to think at boundaries.

Solution

def parse_record(age_str, score_str, active_str):
    age = int(age_str)
    score = float(score_str)
    active = active_str.strip().lower() == "true"
    return {"age": age, "score": score, "active": active}

Tests

def test_age_is_int():
    result = parse_record("25", "98.5", "true")
    assert type(result["age"]) == int
    assert result["age"] == 25

def test_score_is_float():
    result = parse_record("25", "98.5", "true")
    assert type(result["score"]) == float
    assert result["score"] == 98.5

def test_active_true():
    result = parse_record("25", "98.5", "true")
    assert result["active"] == True

def test_active_false():
    result = parse_record("30", "70.0", "false")
    assert result["active"] == False

def test_active_case_insensitive():
    result = parse_record("30", "70.0", "TRUE")
    assert result["active"] == True

Resources