# 214. Type Erasure in Python

#### **🔹 1. Type Hints Are Erased at Runtime**

```python
from typing import List

def process_data(data: List[int]):
    print(f"Received: {data}")

print(process_data.__annotations__)
# Output: {'data': typing.List[int]} (Only visible in annotations, not enforced)
```

🔍 **Key Takeaway:**

* `List[int]` **does not exist at runtime**—only `List` is used.
* Type hints are stored in `__annotations__`, but Python does not enforce them.

***

#### **🔹 2. Generic Type Arguments Are Not Retained**

```python
from typing import List

lst: List[int] = [1, 2, 3]

print(type(lst))  # <class 'list'> (No int information retained)
```

🔍 **Key Takeaway:**

* `List[int]` becomes just `list` at runtime—**type information is erased**.

***

#### **🔹 3. Checking If a Variable is a List (Without Type Info)**

```python
from typing import List

def check_type(data: List[int]):
    print(isinstance(data, list))  # True

check_type([1, 2, 3])
```

🔍 **Key Takeaway:**

* `List[int]` is **completely erased** at runtime, so we only check for `list`.

***

#### **🔹 4. Type Erasure in Function Parameters**

```python
from typing import List

def process_numbers(numbers: List[int]):
    print(type(numbers))  # <class 'list'>

process_numbers(["hello", "world"])  # No error at runtime!
```

🔍 **Key Takeaway:**

* Even though `List[int]` is specified, Python allows `List[str]` at runtime.

***

#### **🔹 5. Type Erasure with Custom Generics**

```python
from typing import TypeVar, Generic

T = TypeVar("T")

class Box(Generic[T]):
    def __init__(self, value: T):
        self.value = value

b = Box(42)
print(type(b))  # <class '__main__.Box'> (No int info retained)
```

🔍 **Key Takeaway:**

* **Generic parameters (`T`) are erased**, so `Box[int]` is just `Box` at runtime.

***

#### **🔹 6. Type Annotations vs. Actual Behavior**

```python
from typing import List

def process_list(lst: List[str]):
    return lst[0].upper()  # Assumes str

print(process_list([1, 2, 3]))  # No type error! Returns '1'
```

🔍 **Key Takeaway:**

* **Python does not enforce type hints at runtime**; they are just for static checks.

***

#### **🔹 7. Checking a Type Using `__orig_bases__`**

```python
from typing import Generic, TypeVar

T = TypeVar("T")

class CustomList(Generic[T]):
    pass

obj = CustomList[int]()
print(obj.__class__.__orig_bases__)  
# Output: (Generic[int],)  (Shows original type argument)
```

🔍 **Key Takeaway:**

* While **type arguments are erased**, they can be accessed using `__orig_bases__`.

***

#### **🔹 8. Type Erasure in Subclassing**

```python
from typing import List

class MyList(List[int]):
    pass

obj = MyList()
print(isinstance(obj, list))  # True
print(isinstance(obj, List[int]))  # TypeError: Subscripted generics cannot be used with isinstance()
```

🔍 **Key Takeaway:**

* `List[int]` **cannot be used** with `isinstance()`, as it's erased at runtime.

***

#### **🔹 9. Recovering Type Information Using `get_type_hints()`**

```python
from typing import List, get_type_hints

class Example:
    def method(self, values: List[int]) -> None:
        pass

hints = get_type_hints(Example.method)
print(hints)  # {'values': typing.List[int], 'return': None}
```

🔍 **Key Takeaway:**

* `get_type_hints()` lets us **recover** erased type information.

***

#### **🔹 10. Type Checking Using `isinstance()` with `typing` Types (Fails)**

```python
from typing import List

lst = [1, 2, 3]
print(isinstance(lst, List))  # TypeError: 'List' is not a class
```

🔍 **Key Takeaway:**

* `List[int]` cannot be used in `isinstance()` checks—only `list` works.

***

#### **🚀 Summary: Type Erasure in Python**

| **Concept**                                    | **Description**                                      |
| ---------------------------------------------- | ---------------------------------------------------- |
| **Type Hints Are Ignored at Runtime**          | Python does not enforce type hints during execution. |
| **Generic Types Become Their Base Type**       | `List[int]` becomes just `list`.                     |
| **No Type Checking for Function Arguments**    | Python allows mismatched types at runtime.           |
| **Type Information Can Be Retrieved**          | Use `__annotations__` or `get_type_hints()`.         |
| **Cannot Use `isinstance()` with `List[int]`** | It raises an error—use `list` instead.               |

***

**🚀 Best Practices**

✅ **Use Type Hints for Readability, Not Enforcement**\
✅ **Use Static Type Checkers (e.g., `mypy`) for Catching Errors**\
✅ **Remember That Generics Are Erased at Runtime**\
✅ **Use `get_type_hints()` for Type Introspection**
