AI Skill Report Card

Introspecting Python Objects

A-82·Aug 12, 2026·Source: Web
14 / 15
Python
class Animal: """Base class for animals.""" pass class Dog(Animal): """A dog.""" pass d = Dog() d.__class__ # <class '__main__.Dog'> d.__dict__ # {} (instance attribute dict) Dog.__name__ # 'Dog' Dog.__qualname__ # 'Dog' Dog.__mro__ # (Dog, Animal, object) Dog.__bases__ # (Animal,) Dog.__doc__ # 'A dog.' Dog.__module__ # '__main__'
Recommendation
Add an example showing practical use in a debugging/serialization tool (e.g., generic repr builder using __dict__ and __class__) to tie introspection to real-world tasks mentioned in the description.
13 / 15

Progress:

  • Identify what kind of introspection is needed (identity, hierarchy, namespace, or metadata)
  • Pick the correct special attribute(s) for that object type
  • Handle attributes that may not exist (use getattr with defaults or hasattr)
  • Distinguish instance-level vs class-level attribute access
  • Validate results against edge cases (built-ins, slots, dynamic classes)

Step 1: Identify the introspection goal

GoalAttribute(s)
Get the class of an instanceobj.__class__
Get a class/function/module's bare name__name__
Get the dotted path to where it was defined__qualname__
Get inheritance chain (method resolution order)__mro__ (classes only, not instances)
Get direct parent classes__bases__
Get instance/class namespace dict__dict__
Get docstring__doc__
Get defining module's name__module__
Get allowed instance attribute names (memory-optimized classes)__slots__

Step 2: Choose instance vs. class access

  • type(obj).__mro__ works; obj.__mro__ does not (MRO is a class-only attribute).
  • obj.__dict__ gives per-instance attributes; type(obj).__dict__ gives the class namespace (a mappingproxy, read-only).
  • Objects using __slots__ have no __dict__ unless __dict__ is explicitly included in slots.

Step 3: Guard against missing attributes

Not all objects define every special attribute (e.g., built-in types, __slots__ classes lack __dict__; lambdas have __qualname__ like <locals>.<lambda>). Always prefer getattr(obj, '__dict__', None) or hasattr in generic tooling.

Recommendation
Include a brief note on __getattr__/__getattribute__ or dir() as complementary introspection tools, since the skill scope mentions reflection code broadly.
17 / 20

Example 1: Inspecting instance vs class dict Input:

Python
class Point: def __init__(self, x, y): self.x = x self.y = y p = Point(1, 2)

Output:

Python
p.__dict__ # {'x': 1, 'y': 2} Point.__dict__ # mappingproxy({'__init__': <function...>, '__dict__': <attribute...>, '__weakref__': <attribute...>, '__doc__': None})

Example 2: Walking the MRO for a diamond hierarchy Input:

Python
class A: pass class B(A): pass class C(A): pass class D(B, C): pass D.__mro__

Output:

Python
(<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)

Example 3: Qualname vs name for nested definitions Input:

Python
class Outer: class Inner: def method(self): pass Outer.Inner.method.__name__ Outer.Inner.method.__qualname__

Output:

Python
'method' 'Outer.Inner.method'

Example 4: Slots preventing dict Input:

Python
class Slotted: __slots__ = ('x',) s = Slotted() s.x = 5 s.__dict__

Output:

Python
AttributeError: 'Slotted' object has no attribute '__dict__'
Recommendation
The workflow checklist is somewhat generic; tighten it to map more directly to the specific attribute-selection table in Step 1 for faster actionability.
  • Use type(obj) rather than obj.__class__ when correctness matters, since __class__ can be overridden (e.g., proxy objects) — but __class__ is fine for typical introspection/debugging.
  • Use __qualname__ over __name__ in logs/tracebacks when nested classes or closures are involved — it disambiguates identically named functions/classes.
  • For serialization or debugging tools, iterate vars(obj) (equivalent to obj.__dict__) rather than accessing __dict__ directly — vars() raises a clearer TypeError when unsupported.
  • When building generic MRO/hierarchy tools, call .__mro__ on the type, not the instance: type(obj).__mro__.
  • Check __module__ alongside __qualname__ to fully disambiguate identically named classes from different modules.
  • Calling obj.__mro__ directly on an instance — it's only defined on classes (via type). Use type(obj).__mro__.
  • Assuming every object has __dict__ — built-ins (int, str) and __slots__-based classes often don't.
  • Mutating type(obj).__dict__ directly — it's a read-only mappingproxy; use setattr(cls, name, value) instead.
  • Confusing __name__ with __qualname__ for nested or locally-defined functions/classes, leading to ambiguous logs.
  • Relying on __module__ for dynamically created classes (e.g., via type() in a factory) — it may default to the factory's module, not the intended logical one.
0
Grade A-AI Skill Framework
Scorecard
Criteria Breakdown
Quick Start
14/15
Workflow
13/15
Examples
17/20
Completeness
17/20
Format
14/15
Conciseness
13/15