How to add property to a class dynamically?

前端 未结 24 2235
梦毁少年i
梦毁少年i 2020-11-22 12:44

The goal is to create a mock class which behaves like a db resultset.

So for example, if a database query returns, using a dict expression, {\'ab\':100, \'cd\'

24条回答
  •  甜味超标
    2020-11-22 13:17

    This is a little different than what OP wanted, but I rattled my brain until I got a working solution, so I'm putting here for the next guy/gal

    I needed a way to specify dynamic setters and getters.

    class X:
        def __init__(self, a=0, b=0, c=0):
            self.a = a
            self.b = b
            self.c = c
    
        @classmethod
        def _make_properties(cls, field_name, inc):
            _inc = inc
    
            def _get_properties(self):
                if not hasattr(self, '_%s_inc' % field_name):
                    setattr(self, '_%s_inc' % field_name, _inc)
                    inc = _inc
                else:
                    inc = getattr(self, '_%s_inc' % field_name)
    
                return getattr(self, field_name) + inc
    
            def _set_properties(self, value):
                setattr(self, '_%s_inc' % field_name, value)
    
            return property(_get_properties, _set_properties)
    

    I know my fields ahead of time so im going to create my properties. NOTE: you cannot do this PER instance, these properties will exist on the class!!!

    for inc, field in enumerate(['a', 'b', 'c']):
        setattr(X, '%s_summed' % field, X._make_properties(field, inc))
    

    Let's test it all now..

    x = X()
    assert x.a == 0
    assert x.b == 0
    assert x.c == 0
    
    assert x.a_summed == 0  # enumerate() set inc to 0 + 0 = 0
    assert x.b_summed == 1  # enumerate() set inc to 1 + 0 = 1
    assert x.c_summed == 2  # enumerate() set inc to 2 + 0 = 2
    
    # we set the variables to something
    x.a = 1
    x.b = 2
    x.c = 3
    
    assert x.a_summed == 1  # enumerate() set inc to 0 + 1 = 1
    assert x.b_summed == 3  # enumerate() set inc to 1 + 2 = 3
    assert x.c_summed == 5  # enumerate() set inc to 2 + 3 = 5
    
    # we're changing the inc now
    x.a_summed = 1 
    x.b_summed = 3 
    x.c_summed = 5
    
    assert x.a_summed == 2  # we set inc to 1 + the property was 1 = 2
    assert x.b_summed == 5  # we set inc to 3 + the property was 2 = 5
    assert x.c_summed == 8  # we set inc to 5 + the property was 3 = 8
    

    Is it confusing? Yes, sorry I couldn't come up with any meaningful real world examples. Also, this is not for the light hearted.

提交回复
热议问题