Overview

17 Data types as objects

Python’s dynamic typing treats classes and types as first-class objects, making type information available and computable at runtime. The chapter shows how type(), __class__, __name__, and __bases__ enable introspection, and contrasts raw type comparisons with the inheritance-aware isinstance() and issubclass(), which are preferred for robust checks. The key takeaway is that classes are ordinary objects (instances of type), so you can compare, store, and pass them around to guide behavior while respecting inheritance.

Beyond explicit checks, Python favors duck typing: code should rely on what an object can do rather than what it is. This encourages flexible, readable designs that lean on EAFP (easier to ask forgiveness than permission) patterns, with exceptions signaling unsupported operations. The chapter also notes that in larger codebases you may temper duck typing with explicit type hints and static analysis to catch interface mismatches earlier, balancing flexibility with maintainability.

Special (dunder) methods let user-defined classes hook into Python’s syntax and semantics to behave like built-ins. Examples include __str__ for readable representations and sequence protocols like __getitem__ to enable iteration and indexing (for instance, a lazy line reader for large files). Building richer container behavior involves methods such as __setitem__, __len__, __add__, __mul__, __delitem__, and list-like APIs (append, insert, extend). While you can implement these from scratch—such as a type-enforcing “typed list”—the chapter recommends the pragmatic route of subclassing built-ins (list, dict) or wrappers (UserList) to inherit complete behavior and override only what you need (for example, enforcing string-only keys and values). Use these capabilities judiciously so custom types feel natural and unsurprising to other Python programmers.

Summary

  • Types/classes are just Python objects.
  • Types can be assigned a variable and compared to other objects for equality.
  • Python has the tools to check the type of objects as needed in your code.
  • Duck typing, which relies on the behavior of objects rather than their type, can let you write more flexible code.
  • Special method attributes have names beginning and ending with “__” (“dunder” methods) can be overridden to change the behavior of user-created classes.
  • Subclassing built-in classes can be used to create similar classes with customized behavior.
  • Python’s use of duck typing, special method attributes, and subclassing makes it possible to construct and combine classes in a variety of ways.

FAQ

What does the built-in type() function return, and what is <class 'type'>?type(obj) returns the object's class (a type object). In Python, classes are themselves objects whose type is type. For example, type(5) is int, and type(int) is type. This is why we say “types are objects.”
When should I use isinstance() instead of comparing types with type()?- Use isinstance(x, C) when you want to accept instances of C or any subclass of C (it respects inheritance).
- type(x) == C only matches exact type C and rejects subclasses.
Example: if E subclasses D, isinstance(e, D) is True, but type(e) == D is False.
How can I find an object's class, its class name, and base classes?- Class of an instance: obj.__class__
- Class name: obj.__class__.__name__
- Base classes: obj.__class__.__bases__ (a tuple). These let you inspect inheritance relationships.
What is duck typing, and when should I prefer it over explicit type checks?Duck typing focuses on behavior, not concrete types: “If it quacks like a duck...” Prefer it when your code only needs certain methods/operations; write to the interface and use EAFP (try/except) rather than prechecking types. In larger codebases, combine this with type hints and static checking to catch mismatches early.
What are special method attributes (dunder methods) and why are they useful?They’re methods with double underscores (like __str__, __getitem__) that Python calls implicitly to provide language features (printing, indexing, iteration, arithmetic, etc.). They let your classes integrate naturally with Python syntax and protocols without client code calling them directly.
How does __str__ change how my objects print?If a class defines __str__(self), Python uses it for user-friendly string conversion (e.g., print(obj), str(obj)). For example, a Color class can return a formatted RGB string so prints show “Color: R=..., G=..., B=...”.
How can __getitem__ make an object behave like a list or iterable?Defining __getitem__(self, index) allows obj[i] access and lets a for-loop repeatedly call it with increasing indices, stopping when IndexError is raised. This enables list-like iteration without storing everything in memory (e.g., reading a file line by line).
What are the limitations of a __getitem__-only iterable like the LineReader example?- Only supports forward, sequential access; random indexing and slicing won’t work.
- Not re-iterable (a second loop won’t restart unless you reset state).
- Multiple nested iterations conflict over shared state.
- Doesn’t implement the iterator protocol (__iter__/__next__), which is the modern, clearer approach for streams.
How can I enforce element types in a list-like class?Options:
- Write a wrapper that checks types in __setitem__/append and delegates storage to an internal list.
- Subclass list and override mutating operations to validate types (concise and retains list features).
- Subclass collections.UserList for a wrapper that exposes the underlying data via self.data. Subclassing built-ins is typically simplest.
How do I create a dict that only allows string keys and values?Subclass dict, override __setitem__ to check both key and value, and ensure initialization can’t bypass checks by validating after super().__init__ in __init__ (or by rebuilding via dict(*args, **kwargs) and inserting through __setitem__). This prevents non-strings from being introduced at construction time.

pro $24.99 per month

  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose one free eBook per month to keep
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime

lite $19.99 per month

  • access to all Manning books, including MEAPs!

team

5, 10 or 20 seats+ for your team - learn more


choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • The Quick Python Book, Fourth Edition ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • The Quick Python Book, Fourth Edition ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • The Quick Python Book, Fourth Edition ebook for free