aosabook/500lines · error · AttributeError

fieldname

Error message

fieldname

What it means

Raised by Base.read_attr in the 03-customizable objmodel. The full lookup order is: instance dict -> class MRO (bindable callables become bound methods) -> a class-level __getattr__. AttributeError(fieldname) is reached only if none resolve the field, meaning the instance lacks the field, the class MRO lacks the attribute/method, AND no __getattr__ is defined on the class (or it re-raised).

Source

Thrown at objmodel/code/03-customizable/objmodel.py:25

        """ Every object has a class. """
        self.cls = cls
        self._fields = fields


    def read_attr(self, fieldname):
        """ read field 'fieldname' out of the object """
        result = self._read_dict(fieldname)
        if result is not MISSING:
            return result
        result = self.cls._read_from_class(fieldname)
        if _is_bindable(result):
            return _make_boundmethod(result, self)
        if result is not MISSING:
            return result
        meth = self.cls._read_from_class("__getattr__")
        if meth is not MISSING:
            return meth(self, fieldname)
        raise AttributeError(fieldname)

    def write_attr(self, fieldname, value):
        """ write field 'fieldname' into the object """
        meth = self.cls._read_from_class("__setattr__")
        return meth(self, fieldname, value)

    def isinstance(self, cls):
        """ return True if the object is an instance of class cls """
        return self.cls.issubclass(cls)

    def callmethod(self, methname, *args):
        """ call method 'methname' with arguments 'args' on object """
        meth = self.read_attr(methname)
        return meth(*args)

    def _read_dict(self, fieldname):
        """ read an field 'fieldname' out of the object's dict """
        return self._fields.get(fieldname, MISSING)

View on GitHub (pinned to fba689d101)

Solutions

  1. Define a __getattr__ method on the Class to supply a default or computed value for the missing field.
  2. Store the field with write_attr or declare it in the Class fields.
  3. Verify the fieldname and that the MRO includes the expected base classes.

Example fix

// before
obj.read_attr('missing')   # AttributeError: missing
// after
# add a class-level __getattr__
MyClass = Class('MyClass', OBJECT, {
    '__getattr__': lambda self, name: 'default',
}, TYPE)
Defensive patterns

Strategy: fallback

Validate before calling

MISSING = object()

def safe_read(obj, fieldname, default=None):
    if obj._read_dict(fieldname) is not MISSING:
        return obj._read_dict(fieldname)
    if obj.cls._read_from_class(fieldname) is not MISSING:
        return obj.cls._read_from_class(fieldname)
    return default

Type guard

def has_field_or_getattr(obj, name):
    MISSING = object()
    return (obj._fields.get(name, MISSING) is not MISSING
            or obj.cls._read_from_class(name) is not MISSING
            or obj.cls._read_from_class('__getattr__') is not MISSING)

Try / catch

try:
    val = obj.read_attr(fieldname)
except AttributeError:
    val = <default>

Prevention

When it happens

Trigger: Reading an attribute that is absent from the instance dict, absent from the class and base classes, and the class defines no __getattr__ to cover it (or its __getattr__ raises AttributeError itself).

Common situations: Implementing __getattr__ but forgetting to handle certain names; deleting an attribute previously set; typos in fieldname; a __getattr__ that itself raises for unknown names.

Related errors


AI-assisted analysis of aosabook/500lines@fba689d101 (2026-08-13). Data as JSON: /api/errors/1673c891c81599eb. Report an issue: GitHub.