Main Ecosystems
HomePython CorePandas ReferenceNumPy ScientificFastAPI & PydanticDjango Enterprise
More Ecosystems
Environment & SetupRequests & HTTPAsyncIO ConcurrencyObject-Oriented OOPPyTorch Deep LearningScikit-Learn MLFlask FrameworkWeb ScrapingDatabase & ORMDevOps & Docker

TypeError: descriptor __get__ for object objects doesnt apply to a type object in Python

Verified FixPython 3.10+Python Native DescriptorsSilo: oop

Quick Fix / Solution Rapide

Handle instance is None in custom descriptor __get__(self, instance, owner) methods to support class-level attribute access.

Root Cause Analysis

This error occurs when Python accesses a custom descriptor (or low-level C-extension property) from a class object directly (e.g. MyClass.my_descriptor), and the descriptor's __get__ implementation strictly expects an instance of the class rather than a type object.

1. The Python Descriptor Protocol Contract

In Python, descriptors implement __get__(self, instance, owner). When accessed on an instance (obj.my_descriptor), instance is the object instance. When accessed on the class (MyClass.my_descriptor), instance is None and owner is the class object (type). If __get__ unconditionally accesses instance.attribute without checking for None, Python raises a TypeError or AttributeError.

2. Custom Validation Descriptors and ORM Fields

Writing custom field descriptors (similar to SQLAlchemy Column or Django Field) that assume an instance always exists.

3. Calling Bound Methods Directly on the Class Without an Instance

Passing the class itself to an unbound descriptor expecting a specific instance type.

4. Mixing @classmethod with @property in Python 3.11+

In Python 3.11+, chaining @classmethod @property was deprecated and removed in Python 3.13 due to descriptor protocol ambiguities.

Reproduction Code (MCVE)

Example: Bug Reproduction
# Simulating a custom descriptor that fails on class-level access
class StrictFieldDescriptor:
    def __get__(self, instance, owner):
        if instance is None:
            raise TypeError("descriptor '__get__' for 'object' objects doesn't apply to a 'type' object")
        return instance._value

class DataRecord:
    field = StrictFieldDescriptor()

# Accessing on class object raises TypeError
DataRecord.field

Solution 1: Return the Descriptor Itself When instance is None

Follow standard Python descriptor protocol: return self when instance is None so class inspection, docstrings, and ORM schemas work.

Example: Recommended Solution
class RobustDescriptor:
    def __init__(self, name=None):
        self.name = name

    def __set_name__(self, owner, name):
        self.name = name

    def __get__(self, instance, owner):
        if instance is None:
            return self  # Return descriptor on class access
        return instance.__dict__.get(self.name, None)

    def __set__(self, instance, value):
        instance.__dict__[self.name] = value

class Person:
    age = RobustDescriptor()

# Class access returns descriptor object
print(f'Class access: {Person.age}')
p = Person()
p.age = 30
print(f'Instance access: {p.age}')

Solution 2: Use classmethod for Class-Level Read-Only Access

If a property must compute a value at the class level, use a @classmethod instead of chaining @property.

Example: Alternative Solution
class Config:
    _version = '2.4.0'

    @classmethod
    def get_version(cls):
        return cls._version

print(f'Class version: {Config.get_version()}')

A common mistake is using getattr(MyClass, 'field') and expecting the raw descriptor without triggering __get__. To get the raw descriptor without invocation, inspect MyClass.__dict__['field'] or use inspect.getattr_static(MyClass, 'field'). Edge cases occur with __set_name__ in Python 3.6+: descriptors can automatically record their assigned attribute name on the owner class. Contrast this error with TypeError: 'property' object is not callable, which occurs when trying to invoke a property with parentheses: obj.name().