Skip to content

Type Introspection

Mental Model

type(x) tells you exactly which class x is -- no more, no less. isinstance(x, SomeClass) is more flexible: it returns True for SomeClass and all its subclasses. Prefer isinstance() for type checks in real code because it respects inheritance; reserve type() for debugging and exact-class comparisons.

type() Function

1. Basic Usage

```python x = 42 print(type(x)) #

y = "hello" print(type(y)) # ```

2. Compare Types

```python x = 42

if type(x) == int: print("x is integer")

if type(x) == str: print("Won't print") ```

isinstance()

1. Better Check

```python x = 42

if isinstance(x, int): print("x is int")

Multiple types

if isinstance(x, (int, float)): print("x is number") ```

2. Inheritance

```python class Animal: pass

class Dog(Animal): pass

dog = Dog()

print(isinstance(dog, Dog)) # True print(isinstance(dog, Animal)) # True

print(type(dog) == Dog) # True print(type(dog) == Animal) # False ```

issubclass()

1. Check Hierarchy

```python class Animal: pass

class Dog(Animal): pass

print(issubclass(Dog, Animal)) # True print(issubclass(Animal, Dog)) # False ```

Callable Check

1. Is Callable

```python def my_func(): return 42

print(callable(my_func)) # True print(callable(42)) # False print(callable(lambda: 1)) # True ```

hasattr()

1. Check Attributes

```python class MyClass: def init(self): self.value = 42

obj = MyClass()

print(hasattr(obj, 'value')) # True print(hasattr(obj, 'missing')) # False ```

dir() and vars()

1. List Attributes

```python class MyClass: def init(self): self.x = 1 self.y = 2

obj = MyClass()

print(dir(obj)) # All attributes print(vars(obj)) # {'x': 1, 'y': 2} ```

Practical Usage

1. Type Validation

```python def validate_int(value): if not isinstance(value, int): raise TypeError("Must be int") return value * 2

print(validate_int(5)) # 10 ```

2. Dynamic Dispatch

```python def process(value): if isinstance(value, int): return value * 2 elif isinstance(value, str): return value.upper() return None

print(process(5)) # 10 print(process("hi")) # "HI" ```


Exercises

Exercise 1. Write a function type_name(obj) that returns the name of the object's type as a string (e.g., "int", "str", "list"). Test with at least 5 different types.

Solution to Exercise 1

```python def type_name(obj): return type(obj).name

print(type_name(42)) # int print(type_name("hello")) # str print(type_name([1, 2])) # list print(type_name((1, 2))) # tuple print(type_name({1: 2})) # dict ```

type(obj).__name__ accesses the name attribute of the type object, giving a clean string representation.


Exercise 2. Demonstrate the difference between type() and isinstance() with class inheritance. Create a base class Animal and a subclass Dog, then show how each function behaves when checking a Dog instance against Animal.

Solution to Exercise 2

```python class Animal: pass

class Dog(Animal): pass

dog = Dog()

type() checks exact type

print(type(dog) == Dog) # True print(type(dog) == Animal) # False

isinstance() checks inheritance chain

print(isinstance(dog, Dog)) # True print(isinstance(dog, Animal)) # True ```

type() checks the exact type only. isinstance() checks the entire inheritance chain, making it the preferred choice for most type checking.


Exercise 3. Write a function describe(obj) that uses isinstance() to return different descriptions based on the object's type: "number" for int or float, "text" for str, "collection" for list, tuple, or set, and "unknown" otherwise.

Solution to Exercise 3

```python def describe(obj): if isinstance(obj, (int, float)): return "number" elif isinstance(obj, str): return "text" elif isinstance(obj, (list, tuple, set)): return "collection" else: return "unknown"

print(describe(42)) # number print(describe("hello")) # text print(describe([1, 2, 3])) # collection print(describe(None)) # unknown ```

Passing a tuple of types to isinstance() checks if the object is an instance of any of the listed types.