Search code examples
pythonassignment-operatorclass-method

Classmethod Item Assignment


So I have essentially created a dictionary Class that uses classmethods for all of its magic methods that looks like this:

class ClassDict(object):
    _items = {}

    @classmethod
    def __getitem__(cls, key):
        return cls._items[key]

    @classmethod
    def __setitem__(cls, key, val):
        cls._items[key] = val

    @classmethod
    def __len__(cls):
        return len(cls._items)

    @classmethod
    def __delitem__(cls, key):
        cls._items.__delitem__(key)

    @classmethod
    def __iter__(cls):
        return iter(cls._items)

And so when I try to assign an item to it:

ClassDict['item'] = 'test'

I get an error saying TypeError: 'type' object does not support item assignment, but if I call the actual method, __setitem__ like so it works fine:

ClassDict.__setitem__('item', 'test')

And this also works:

ClassDict().__setitem__('item', 'test')

Is there anything I am doing wrong here that would prevent the first example from working? Is there any way I can fix this issue?


Solution

  • To get the behavior desired of being able to do:

    ClassDict['item'] = 'test'
    

    I had to implement the special methods as a metaclass instead as Martijn pointed out.

    So my final implementation looks like this:

    class MetaClassDict(type):
        _items = {}
    
        @classmethod
        def __getitem__(cls, key):
            return cls._items[key]
    
        @classmethod
        def __setitem__(cls, key, val):
            cls._items[key] = val
    
        @classmethod
        def __len__(cls):
            return len(cls._items)
    
        @classmethod
        def __delitem__(cls, key):
            cls._items.__delitem__(key)
    
        @classmethod
        def __iter__(cls):
            return iter(cls._items)
    
    
    class ClassDict(object):
        __metaclass__ = MetaClassDict