Using __delitem__ with a class object rather than an instance in Python

class, class-method, instance, python

Solution

When you write `del obj[key]`, Python calls the `__delitem__` method of the class of `obj`, not of `obj`. So `del obj[key]` results in `type(obj).__delitem__(obj, key)`.

In your case, that means `type(Foo).__delitem__(Foo, 'abcd')`. `type(Foo)` is `type`, and `type.__delitem__` is not defined. You can't modify `type` itself, you'll need to change the type of `Foo` itself to something that does.

You do that by defining a new metaclass, which is simply a subclass of `type`, then instructing Python to use your new metaclass to create the `Foo` class (not instances of `Foo`, but `Foo` itself).

class ClassMapping(type):
    def __new__(cls, name, bases, dct):
        t = type.__new__(cls, name, bases, dct)
        t._instances = {}
        return t
    def __delitem__(cls, my_str):
        del cls._instances[my_str]

class Foo(object):
    __metaclass__ = ClassMapping
    def __init__(self, my_str):
        n = len(Foo._instances) + 1
        Foo._instances[my_str] = n
        print "Now up to {} instances".format(n)

Changing the metaclass of `Foo` from `type` to `ClassMapping` provides `Foo` with

- a class variable `_instances` that refers to a dictionary

- a `__delitem__` method that removes arguments from `_instances`.

Problem

I'd like to be able to use `__delitem__` with a class-level variable. My use case can be found here (the answer that uses `_reg_funcs`) but it basically involves a decorator class keeping a list of all the functions it has decorated. Is there a way I can get the class object to support `__delitem__`? I know I could keep an instance around specially for this purpose but I'd rather not have to do that. ``` class Foo(object): _instances = {} def __init__(self, my_str): n = len(self._instances) + 1 self._instances[my_str] = n print "Now up to {} instances".format(n) @classmethod def __delitem__(cls, my_str): del cls._instances[my_str] abcd = Foo('abcd') defg = Foo('defg') print "Deleting via instance..." del abcd['abcd'] print "Done!\n" print "Deleting via class object..." del Foo['defg'] print "You'll never get here because of a TypeError: 'type' object does not support item deletion" ```

Original source

Related problems