Python Essentials for AI Engineers · Lesson 9 of 36
What is Type Casting?
What is Type Casting?
Type casting (also called type conversion) means explicitly converting a value from one type to another. Python doesn't do this automatically in most cases — you must be explicit.
# Each built-in type has a corresponding constructor function
int("42") # str → int: 42
float("3.14") # str → float: 3.14
str(100) # int → str: "100"
bool(0) # int → bool: False
list((1, 2, 3)) # tuple → list: [1, 2, 3]
tuple([1, 2, 3])# list → tuple: (1, 2, 3)str → int and str → float
Converting strings from user input or API responses is the most common use case.
# int(): base 10 by default
age = int("28") # 28
tokens = int("4096") # 4096
# int() with different bases
binary_val = int("1010", 2) # "1010" in base 2 → 10
hex_val = int("FF", 16) # "FF" in base 16 → 255
# float()
score = float("0.92") # 0.92
temperature = float("0") # 0.0
# float → int: truncates (does NOT round)
int(3.9) # 3
int(-3.9) # -3
# round() for proper rounding
round(3.9) # 4Safe Casting with try/except
Input from users or external APIs can be malformed. Always validate before casting.
def safe_int(value: str, default: int = 0) -> int:
"""Convert string to int, returning default on failure."""
try:
return int(value)
except (ValueError, TypeError):
return default
print(safe_int("42")) # 42
print(safe_int("abc")) # 0 — invalid
print(safe_int("3.14")) # 0 — float string can't go direct to int
print(safe_int(None)) # 0 — None raises TypeError
def safe_float(value: str, default: float = 0.0) -> float:
"""Convert string to float, returning default on failure."""
try:
return float(value)
except (ValueError, TypeError):
return default
print(safe_float("3.14")) # 3.14
print(safe_float("3.14abc")) # 0.0 — invalidbool Conversion
Every Python object has a boolean value. bool() makes it explicit.
# Falsy values: False when converted to bool
bool(0) # False
bool(0.0) # False
bool("") # False
bool([]) # False
bool({}) # False
bool(None) # False
bool(set()) # False
# Truthy values: True when converted to bool
bool(1) # True
bool(-1) # True
bool("hello") # True
bool([0]) # True — non-empty list, even if contents are falsy
bool(0.0001) # True
# Practical use: guard LLM outputs
response = ""
if not response:
response = "No response generated."Sequence Type Conversions
# list ↔ tuple ↔ set
numbers = [1, 2, 2, 3, 3, 3]
as_tuple = tuple(numbers) # (1, 2, 2, 3, 3, 3) — immutable
as_set = set(numbers) # {1, 2, 3} — deduplicated, unordered
back_list = list(as_set) # [1, 2, 3] (order not guaranteed)
# str ↔ list of characters
chars = list("warfarin") # ['w', 'a', 'r', 'f', 'a', 'r', 'i', 'n']
word = "".join(chars) # "warfarin"
# split / join — most common string-list conversion
sentence = "patient takes warfarin daily"
words = sentence.split() # ["patient", "takes", "warfarin", "daily"]
rejoined = " | ".join(words) # "patient | takes | warfarin | daily"AI and ML Patterns
Parsing LLM API Responses
import json
def parse_llm_response(response: dict) -> dict:
"""
LLM APIs return usage counts as ints and scores as floats.
Parse and cast defensively.
"""
usage = response.get("usage", {})
return {
"prompt_tokens": int(usage.get("prompt_tokens", 0)),
"completion_tokens": int(usage.get("completion_tokens", 0)),
"total_tokens": int(usage.get("total_tokens", 0)),
"model": str(response.get("model", "unknown")),
}
raw_response = {
"model": "gpt-4o",
"usage": {"prompt_tokens": "120", "completion_tokens": "80", "total_tokens": "200"},
}
parsed = parse_llm_response(raw_response)
print(parsed["total_tokens"] * 2) # 400 — now arithmetic worksPreparing Data for NumPy
import numpy as np
# CSV data comes in as strings — must cast before NumPy operations
csv_rows = [
["0.92", "0.78", "0.61"],
["0.45", "0.89", "0.73"],
]
# Manual cast: nested list comprehension
matrix = [[float(x) for x in row] for row in csv_rows]
arr = np.array(matrix) # NumPy float64 array
print(arr.mean()) # Works — all floats
# Cleaner: np.array with dtype cast
arr2 = np.array(csv_rows, dtype=float) # NumPy casts strings internally
print(arr2.shape) # (2, 3)Encoding Labels for Classification
# String labels → int indices for ML models
drug_classes = ["anticoagulant", "antidiabetic", "antihypertensive"]
label_to_idx = {label: idx for idx, label in enumerate(drug_classes)}
idx_to_label = {idx: label for label, idx in label_to_idx.items()}
labels = ["antidiabetic", "anticoagulant", "antidiabetic"]
encoded = [label_to_idx[label] for label in labels] # [1, 0, 1]
# Decode predictions back to strings
predictions = [0, 1, 2]
decoded = [idx_to_label[p] for p in predictions]
# ["anticoagulant", "antidiabetic", "antihypertensive"]Common Pitfalls
# Pitfall 1: int() cannot convert a float-formatted string directly
int("3.14") # ValueError! Must go via float first
int(float("3.14"))# 3 — two-step conversion
# Pitfall 2: float → int truncates, not rounds
int(2.9) # 2, not 3
int(-2.9) # -2, not -3 (truncates toward zero)
round(2.9) # 3 — use round() when you want rounding
# Pitfall 3: bool(value) vs value is True
x = 1
bool(x) == True # True — numeric truthy
x is True # False — 1 is not the True singleton
# Pitfall 4: list("abc") gives characters, not words
list("warfarin") # ['w', 'a', 'r', 'f', 'a', 'r', 'i', 'n']
"warfarin".split() # ["warfarin"] — single-element listType Casting Quick Reference
| From | To | Function | Notes |
|---|---|---|---|
| str | int | int("42") | Fails on float strings — use int(float(s)) |
| str | float | float("3.14") | Handles integers too |
| int / float | str | str(42) | Always works |
| int | float | float(5) | Exact — 5.0 |
| float | int | int(3.9) | Truncates toward zero |
| anything | bool | bool(x) | Empty/zero → False |
| list | tuple | tuple([1,2]) | Immutable |
| tuple | list | list((1,2)) | Mutable |
| list/tuple | set | set([1,1,2]) | Removes duplicates |
| str | list[str] | s.split() | Split on whitespace |
| list[str] | str | " ".join(lst) | Join with separator |