Home > front end >  Python: __setattr__ as class-method // self.__dict__ assignment on a metaclass
Python: __setattr__ as class-method // self.__dict__ assignment on a metaclass

Time:09-17

I want to create a simple Class which just stores / holds data as class attributes without creating an instance as an object.

Simple as that which can be accessed from everywhere in my code:

class DATA:
    foo = {}
    bar = {}

Now I wanted to go one step further and always save changes to foo and bar in a file, e.g. shelve, still without creating an object / instance.

My initial thought was something like this:

class DATA2:
    foo = {}
    bar = {}
    _shelve = False

    def __setattr__(self, name, value):
        if self._shelve is False:
            self.__dict__['_shelve'] = shelve.open('datastorage.shelve')

        self.__dict__['_shelve'][name] = value
        self.__dict__[name] = value

But __setattr__ cannot be used like this using the self argument. And it seems there is no __setattr__ method on a class instance.

My second approach was to use a meta class which creates a class instance in the background hiding it from the code:

class _DATA_MetaClass(type):
    foo = {}
    bar = {}
    _shelve = False

    def __setattr__(self, name, value):
        if self._shelve is False:
            self.__dict__['_shelve'] = shelve.open('datastorage.shelve')

        self.__dict__['_shelve'][name] = value
        self.__dict__[name] = value

class DATA(object):
    __metaclass__ = _DATA_MetaClass

DATA.x = 'val'

This does not work, it yields:

TypeError: 'dictproxy' object does not support item assignment

Why is that?

CodePudding user response:

You can use the __setattr__ method of the super class (which is type) to set the custom attributes:

class _DATA_MetaClass(type):
    foo = {}
    bar = {}
    _shelve = False

    def __setattr__(self, name, value):
        if self._shelve is False:
            super(_DATA_MetaClass, self).__setattr__('_shelve', shelve.open('datastorage.shelve'))

        self._shelve[name] = value
        super(_DATA_MetaClass, self).__setattr__(name, value)
  • Related