Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically add properties to instances in Python [duplicate]

I've got essentially an elaborate wrapper around a list of dictionaries:

class Wrapper(object):
    def __init__(self, data):
        self.data = data

    def get(self, attr):
        return [d[attr] for d in self.data]

So,

Wrapper([{'x': 23}, {'x': 42}, {'x': 5}]).get('x')

returns [23, 42, 5]. Now I want to assign shorthand properties, so that Wrapper.x will return the same as Wrapper.get('x'). I don't know what keys are present in the data a priori, so my current approach is (adapted from this question:

class Wrapper(object):
    def __init__(self, data):
        self.data = data
        for key in data[0].keys():
            setattr(self, key, property(lambda self: self.get(key)))

So, assumption is that all elements of data have the same keys and they're all valid identifiers in python. But then, Wrapper(...).x returns <property at 0x10a3d4838> What am I doing wrong?

like image 858
Manuel Ebert Avatar asked Dec 21 '22 22:12

Manuel Ebert


1 Answers

You can actually do this easily by just changing the name of your function:

>>> class Wrapper(object):
...     def __init__(self, data):
...         self.data = data
...     def __getattr__(self, attr):
...         return [d[attr] for d in self.data]
... 
>>> Wrapper([{'x': 23}, {'x': 42}, {'x': 5}]).x
[23, 42, 5]

The __getattr__() special method is called whenever you request an attribute that doesn't exist. The only potential issue here is that you could override this by assigning an attribute. If you need to avoid that, simply override __setattr__() as well to stop that from happening.

like image 121
Gareth Latty Avatar answered Mar 22 '23 23:03

Gareth Latty