Наследование метода виртуального класса - как вызвать его из базового класса? - PullRequest
0 голосов
/ 29 мая 2018

Пусть B наследуется от A.Предположим, что часть поведения B зависит от атрибута класса cls_x, и мы хотим установить эту зависимость во время создания объектов B.Поскольку это не простая операция, мы хотим обернуть ее в метод класса, который вызовет конструктор.Пример:

class B(A):
  cls_x = 'B'

  @classmethod
  def cm(cls):
    return cls.cls_x

  def __init__(self):
    self.attr = B.cm()

Проблема: cm и __init__ всегда будут выполнять одни и те же действия, и их поведение должно оставаться одинаковым в каждом производном классе.Таким образом, мы хотели бы поместить их обоих в базовый класс, а , а не , определить его в любом из производных классов.Единственным отличием будет вызывающий cm - либо A, либо B (или любой из B1, B2, каждый из которых наследуется от A), независимо от того, что создается.Поэтому нам хотелось бы получить что-то вроде этого:

class A:
  cls_x = 'A'

  @classmethod
  def cm(cls):
    return cls.cls_x

  def __init__(self):
    self.attr = ClassOfWhateverIsInstantiated.cm()  #how to do this?

class B(A):
  cls_x = 'B'

Мне кажется, что это либо что-то очень простое, я упускаю механику наследования Python, либо весь вопрос должен решаться совершенно по-другому.

Это отличается от этого вопроса, поскольку я не хочу переопределять метод класса, но полностью перенесу его реализацию в базовый класс.

Ответы [ 2 ]

0 голосов
/ 29 мая 2018

Посмотрите на это так: ваш вопрос по сути "Как мне получить класс экземпляра?"Ответ на этот вопрос заключается в использовании функции type:

ClassOfWhateverIsInstantiated = type(self)

Но вам даже не нужно этого делать, потому что методы классов могут вызываться напрямую через экземпляр:

def __init__(self):
    self.attr = self.cm()  # just use `self`

Это работает, потому что методы класса автоматически ищут класс экземпляра для вас.Начиная с документы :

[Classmethod] можно вызывать либо для класса (например, C.f()), либо для экземпляра (например, C().f()).Экземпляр игнорируется, за исключением его класса.

0 голосов
/ 29 мая 2018

Для ClassOfWhateverIsInstantiated вы можете просто использовать self:

class A:
  cls_x = 'A'

  @classmethod
  def cm(cls):
    return cls.cls_x

  def __init__(self):
    self.attr = self.cm()  # 'self' refers to B, if called from B

class B(A):
  cls_x = 'B'

a = A()
print(a.cls_x) # = 'A'
print(A.cls_x) # = 'A'

b = B()
print(b.cls_x) # = 'B'
print(B.cls_x) # = 'B'

Чтобы понять это, просто помните, что класс B наследует методы класса A. Поэтому, когда __init__() вызывается во время создания экземпляра B, вызывается в контексте класса B, к которому относится self.

...