Question What is the proper way to wrap data in Python? Is the __init__ and self. boilerplate needed?
As a class Sometimes I wish to create classes that represent Data, but don't have complex computational mechanics inside. For example:
class DataClass:
  def __init__(self, a, b, c):
    self.a = b
    self.b = b
    self.c = c
  def sum(self):
    return self.a + self.b + self.c
dc = DataClass(1,2,3)
print(dc.sum())
I dislike this code, the mathematics of a + b + c is hard to read due to the self. and the constructor is boilerplate. Moreover, I would create this class whenever I noticed that a tuple or dict around a, b and c is getting messy. In particular, tuples are ugly when the returned values change in amount or order, as happend with cv2.findContours between opencv versions 3 and 4 (returning 3, respectively 2 values). Lastly, I often copy-paste boilerplate stuff, easily allowing for painful mistakes, as is the case here with self.a = b.
As a function Therefore I often do something like this:
def DataFunc(a, b, c):
  class Result:
    def sum(self):
      return a + b + c
  return Result()
df = DataFunc(1,2,3)
print(df.sum())
It works and it is significantly more transparent (imho), but also a bit weird w.r.t. types, i.e.
rf2 = ResultFunc(1,2,3)
print(type(rf) == type(rf2)) # -> False
Moreover, the data members are not accessible (rf.a, rf.b, etc). 
As a class with an annotator Finally, one can create an annotator to add the constructor:
def add_constructor(*vars):
    def f(class_):
        def init(self, *args, **kwargs):
            unasigned = set(vars[len(args):]) - set(kwargs.keys())
            if len(unasigned) > 0:
                raise ValueError(f"Missing argument(s): {' '.join(unasigned)}")
            for name, value in zip(vars, args):
                setattr(self, name, value)
            for name, value in kwargs.items():
                setattr(self, name, value)
        setattr(class_, '__init__', init)
        return class_
    return f
@add_constructor('a', 'b', 'c')
class DataAnnot:
    def sum(self):
        return self.a + self.b + self.c
da = DataAnnot(1,2,c=3)
print(da.sum())
