Search code examples
pythonlistobjectsetattr

Python create list of objects from list of 2 elements lists


I have a list of lists of 2-element lists, e.g.:

[[[a, b], [c, d], [e, f]], [[g, h], [i, j], [k, l]]] 

and I want to create a list of objects with attributes from the two-element lists, like this:

[(obj.a = b, obj.c=d, obj.e=f), (obj.g=h, obj.i=j, obj.k=l)]

I tried many ways, but seems I really don't know how, creating an object like a = object() and setting attrs via object.__setattr__ didn't work for me.


Solution

  • You can't set arbitrary attributes on object instances:

    >>> a = object()
    >>> a.b = 'c'
    
    Traceback (most recent call last):
      File "<pyshell#56>", line 1, in <module>
        a.b = 'c'
    AttributeError: 'object' object has no attribute 'b'
    

    Howver, you can create a Generic class that will allow you to:

    class Generic(object):
        pass
    

    Then, assuming your list contains string pairs:

    l = [[['a', 'b'], ['c', 'd'], ['e', 'f']], 
         [['g', 'h'], ['i', 'j'], ['k', 'l']]]
    

    you can iterate over it as follows:

    out = []
    for ll in l:
        obj = Generic()
        for attr, val in ll:
            setattr(obj, attr, val)
        out.append(obj)
    

    Alternatively, you can use the three-argument form of type to create arbitrary classes, then create instances of those:

    out = [type("Generic", (object,), dict(ll))() for ll in l]
    

    Note that e.g.

    >>> dict(l[0])
    {'a': 'b', 'c': 'd', 'e': 'f'}
    

    Finally, if you have an actual (not generic) object that takes e.g. a, c, e as arguments to __init__:

    class Actual(object):
        def __init__(self, a, c, e):
            self.a = a
            self.c = c
            self.e = e
    

    You can use dictionary unpacking to create an instance from the sub-list e.g. l[0]:

    obj = Actual(**dict(l[0]))