Python: как к inherite и переопределению

Рассмотрите эту ситуацию:

Я получаю объект типа A который имеет функцию f. Т.е.:

class A:
   def f(self):
      print 'in f'
   def h(self):
      print 'in h'

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

class B(A):
     def __init__(self, a):
        #something here
     ....

     def f(self):
         print 'in B->f'

и использование было бы:

def main(a):
   b = B(a)
   b.f()   #prints "in B->f"
   b.h()   #print "in h"

То, что я хочу, является своего рода конструктором копии, который получает родителя текущего класса (A) и возвращает экземпляр этого класса (B).

Как дела такая вещь? Как был бы __init__ взгляд метода?

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

15
задан msw 16 May 2010 в 13:41
поделиться

3 ответа

То, как вы создаете объект подкласса B «на основе» одного из класса A , зависит исключительно от того, как последний поддерживает состояние , если оно есть, и как вам лучше всего добраться до этого состояния и скопировать его. В вашем примере экземпляры A не имеют состояния, поэтому нет абсолютно никакой работы, которую вам нужно выполнять в B 's ' __ init __ '. В более типичном примере, скажем:

class A(object):
   def __init__(self):
     self._x = 23
     self._y = 45
   def f(self):
      print 'in f,', self._x
   def h(self):
      print 'in h,', self._y

состояние будет в двух атрибутах экземпляра _x и _y , так что это то, что вам нужно скопировать:

class B(A):
     def __init__(self, a):
        self._x = a._x
        self._y = a._y

     def f(self):
         print 'in B->f,', self._x

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

Обычно вы ищите аспекты состояния экземпляра A в A '__ init __' , потому что самый нормальный, простой код Python устанавливает состояние экземпляра в инициализация (атрибуты могут быть добавлены и удалены позже или даже из кода вне тела класса, но это не часто и обычно не рекомендуется).

Можно добавить немного «магии» (программирование на основе интроспекции), например ..:

class B1(A):
    def __init__(self, a):
        try: s = a.__getstate__()
        except AttributeError: s = a.__dict__
        try: self.__setstate__(s)
        except AttributeError: self.__dict__.update(s)

getstate - это специальный метод, который классы могут определять - если они это делают, он используется (например, путем травления) для «получения состояния» их экземпляров с целью сериализации (в противном случае, __ dict __ экземпляра считается «состоянием» экземпляра). Он может вернуть dict (в этом случае .Вызов update обновляет состояние self ), но он также может возвращать что-нибудь еще, если класс также определяет __ setstate __ , которое его принимает (так что этот код сначала пробует этот маршрут, прежде чем вернуться к возможности обновления). Обратите внимание, что в этом случае один или оба специальных метода будут унаследованы от A - я бы не стал определять / переопределять их в B (если нет дополнительных тонких целей для таким образом, конечно ;-).

Стоит ли использовать эти четыре строки «магии» вместо простых заданий, которые я впервые предложил? В большинстве случаев нет - предпочтительнее простота. Но если A делает что-то особенное или подвергается воздействию внешнего кода, изменяющего его состояние, это решение может быть более мощным и универсальным (это то, что вы покупаете, принимая его усложнение). Итак, вы должны знать, применим ли последний случай (а затем «приступайте к большим пушкам» специальных методов, связанных с состоянием), или если A и его экземпляры являются «довольно обычными ванильными», в этом случае я настоятельно рекомендую вместо этого выбирать простоту и ясность.

11
ответ дан 1 December 2019 в 04:00
поделиться

Попробуйте следующее:

class A:
  def f(self):
    print("in f")

  def h(self):
    print("in h")

class B(A):
  def f(self):
    print("in B:f")

def test(x):
  x.f()
  x.h()

test(A())
test(B())

Обратите внимание, я использую Python 3, что является причиной того, что print принимает аргументы в скобках.

Output:

in f
in h
in B:f
in h
5
ответ дан 1 December 2019 в 04:00
поделиться

Необходимо поместить аргумент self в список аргументов, например методов в python.

Как только вы это сделаете, он просто будет работать, потому что все методы виртуальны в python.

2
ответ дан 1 December 2019 в 04:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: