MyClass.attr VS тип (самостоятельно) .attr VS отдельный @classmethod - PullRequest
0 голосов
/ 10 февраля 2019

Скажем, у меня в классе есть метод (с нормальной границей), который должен обращаться к переменным класса (например, к счетчику в __init__).Если я хочу изменить переменные класса, я вижу три возможности:

  1. Использование type(self) или self.__class__ (после прочтения this я выбрал type вместо __class__, так как я использую Python 3, чтобы классы «старого стиля» не применялись)
  2. Используйте имя класса.Это работает хорошо, если имя не отскок.
  3. написать @classmethod специально для изменения переменных класса.Это самый сложный, но также и самый понятный (IMO) подход.

Три метода будут написаны так:

class MyClass:
    counter = 0

    def f1(self):
        type(self).counter += 1

    def f2(self):
        MyClass.counter += 1

    def f3(self):
        self._count()
    @classmethod
    def _count(cls):
        cls.counter += 1

Есть ли ясный«лучший» вариант, и какой это или они все более или менее эквивалентны, и это просто «что мне нравится больше всего»?Меняет ли наследство что-нибудь?

1 Ответ

0 голосов
/ 12 февраля 2019

Если вы извлекаете классы из класса, определяющего вашу переменную (и, вероятно, метода, присваивающего ей), используя type(self), вы сохраняете (новое значение) атрибут в фактическом классе объекта.Это может быть очень полезно, но в вашем примере это , безусловно, неправильно .

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

Использование имени класса является простым, идиоматическим ответом и позволяет избежать путаницы с подклассами.В отсутствие беспокойства по поводу повторного связывания этого имени это должно быть по умолчанию даже без какого-либо наследования.Если вас это беспокоит, вы можете stash объект класса двумя различными способами:

class A:
  counter=0

  # use the magic behind super():
  def _count1(): __class__.counter+=1

  # inject the class object:
  @staticmethod
  def _count2(cls): cls.counter+=1
A._count2.__defaults__=A,

# inject via a closure:
def capture(cls):
  def _count(): cls.counter+=1
  return _count
A._count3=staticmethod(capture(A))

Трюк __class__, конечно, можно использовать напрямую, без метода-оболочки, но это немного некрасиво;внутренне это очень похоже на последний подход с capture.Одна вещь, которая не работает, - это попытаться создать функцию, которая ссылается на словарь класса , поскольку они защищены по причинам оптимизации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...