2

our project collects a bunch of information on an object from a bunch of different sources and for auditing and for resolving conflicts between our data sources we need to keep a bunch of meta data about each attribute

age = 21
age_metadata = {
     'source' : 'office gossip',
     'relability' : 0 
    {

the problem is the classes start to look like this.

class Person
    def __init__(self, id, ):
       self.id = id
       self.id_meta = None
       self.age = None
       self.age_meta = None
       self.name = None

which looks ugly and doubles the number of attributes everything has so what I want is to nest the metadata under each attribute. so if I need it I can call bob.age.meta instead of bob.age_meta and I want to do this while leaving the attributes more or less unchanged. so I want something that always me to use it like:

def main():
    bob = Person(1)
    bob.age.meta = 'random metadata'
    bob.age = 30
    assert bob.age.meta == 'random metadata'

Now I think this should be possible using a combo of a descriptor class to intercept the assignment + some monkey patching/ metaclassing magic to preserve the metadata.. but I'm new to all these features and am getting very lost. here is my current sketch.long way from working code:

class AttributeWithMeta(object):
    """interceot attribute fucntions"""

    def __get__(self, instance, owner):
        return self._value

    def __set__(self, instance, value):
        """take  attribute and somehow replace it with monkey patched version"""
        self._value = magic(value,meta)

    @staticmethod
    def magic(value, meta):
        """adds meta attribute to objects regardless of type"""
        return  value_with_meta


class Person(object):
    age = AttributeWithMeta()

    def __init__(self, id):
        self.id = id

Am I going in the right direction? is there some other way to do this that I'm missing? Am I trying to do the impossible here?

P.S worst case age.get_meta() would be acceptable if attributes are problematic.

1
  • Alternately, this looks like a good thing to model in a database. You could do sqlalchemy + sqlite for instance. Commented Nov 3, 2016 at 15:38

1 Answer 1

1
bob.age.meta
   ^   ^
   |   |_______ This lookup can be managed by type(bob.age) class
   |
   |___________ This lookup can be managed by type(bob) class, i.e. Person

The attribute access of .meta is handled entirely by the bob.age object, so your Person class gets no say in the matter here.

By defining descriptors on Person class, you can control how setting/getting/deleting the age attribute behaves on a Person instance. You own the dot between a person instance and an attribute, and can do anything you want there. But that power does not reach as far as the 2nd dot - i.e. the . between age and meta.

If you want bob.age to return literally the integer 30, then you are going to have a hard time getting bob.age.meta to do anything but raise AttributeError. That's because you would need a descriptor to be defined on the int class, now, and monkey-patching built-in types is not possible in python. Not without terrible and unreliable hacks, anyway.

If you are happy for bob.age to return some kind of container of an object and the associated metadata, then what you want is possible with descriptors on the Person class. But if you want bob.age to return only the object, and bob.age.meta to return only the metadata, then I think you're barking up the wrong tree.

A much less complicated design would be for each Person instance to have a meta dict directly, so that you could look up for example bob.meta['age'] for the metadata related to bob's age attribute.

Sign up to request clarification or add additional context in comments.

1 Comment

thanks so I think I'm on the right track, I'm ok if age no longer the built in type but is instead a container that defers all of its methods except __set__ and meta to its ._value attribute which it defers it ._meta

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.