Избегайте `self` и переменной переменной в классах - PullRequest
0 голосов
/ 18 октября 2019

Вопрос Как правильно обернуть данные в Python? Нужен ли шаблон __init__ и self.?

Как класс Иногда я хочу создать классы, которые представляют Данные, но не имеют сложной вычислительной механики внутри. Например:

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())

Мне не нравится этот код, математика a + b + c трудна для чтения из-за self., а конструктор является шаблонным. Более того, я создаю этот класс всякий раз, когда замечаю, что кортеж или диктат вокруг a, b и c становится беспорядочным. В частности, кортежи выглядят некрасиво, когда возвращаемые значения изменяются в количестве или порядке, как это происходит с cv2.findContours между версиями 3 и 4 opencv (возвращая 3 или 2 значения соответственно). Наконец, я часто копирую и вставляю шаблоны, легко допуская болезненные ошибки, как в случае с self.a = b.

как функция Поэтому я часто делаю что-то вроде этого:

def DataFunc(a, b, c):
  class Result:
    def sum(self):
      return a + b + c
  return Result()


df = DataFunc(1,2,3)

print(df.sum())

Работает и значительно прозрачнее (imho), но также немного странно по отношению к типам, т. Е.

rf2 = ResultFunc(1,2,3)
print(type(rf) == type(rf2)) # -> False

Кроме того, элементы данных недоступны (rf.arf.b и т. Д.)

Как класс с аннотатором Наконец, можно создать аннотатор для добавления конструктора:

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())
...