0

I'm trying to replicate mongoengine functionality that lets you define field objects that can be used like normal python objects in the code. My idea is to create a FieldHolder class that contains the value and (de)serialization logic, and a Document object with overridden __setattr__ and __getattribute__ methods.

In my code draft, if I set x.h to some value, this value gets correctly assigned to x.h._value. When I get x.h, I correctly get x.h._value.

However, I would also like get h as a FieldHolder object and not as its value. I have tried using object.__getattribute__ (inside serialize method), but I'm still getting h._value (object.__getattribute__(self, 'h') returns abc). What am I doing wrong? Thanks

class FieldHolder:

    _value = None
    # Some serialization and deserialization methods


class Document(object):

    h = FieldHolder()

    def __setattr__(self, key, value):
        attr = getattr(self, key, None)
        if attr is not None and isinstance(attr, FieldHolder):
            attr._value = value
        else:
            super().__setattr__(key, value)

    def __getattribute__(self, key):
        val = super().__getattribute__(key)
        if isinstance(val, FieldHolder):
            return val._value
        else:
            return val

    def serialize(self):
        res = {}
        for name, value in vars(self).items():
            obj = object.__getattribute__(self, name)  # not working as expected
            if isinstance(obj, FieldHolder):
                res[name] = value
        return res


x = Document()
x.h = "abc"  # h._value is now "abc"
print(x.h)   # prints "abc"
s = x.serialize() # should return {'h': 'abc'} but returns {}
print(s)
rickyalbert
  • 2,552
  • 4
  • 21
  • 31
  • Why does `serialize` need the `FieldHolder` instance, rather than simply letting `res['h'] = self.h`? If there is a difference, you probably want to make `FieldHolder` a descriptor, rather than overriding anything in `Document`. – chepner Apr 08 '19 at 15:51
  • The `_value` attribute is a class attribute, so doesn't show up in `vars(FieldHolder())`, only in `vars(FieldHolder)`, which is why it isn't showing up when you call `vars(self)`. You can fix that by having `_value` as an instance attribute on `FieldHolder`, i.e. in the constructor for `FieldHolder`, have `self._value = None` – codelessbugging Apr 08 '19 at 15:55

0 Answers0