Вопрос о python и классах

#python #class #function

#python #класс #функция

Вопрос:

У меня есть базовый класс и несколько производных на Python:

 class Base:
   def Foo(self):
      pass

# First derived class
class Der1(Base):
   def OwnFoo(self):
      # Do something 1
   def OwnFoo2(self):
      # Do something 2

   def Foo(self):
      # Do something 3

# Second derived class
class Der2(Base):
   def OwnFoo(self):
      # Do something 1
   def OwnFoo2(self):
      # Do something 2

   def Foo(self):
      # Do something 3
  

Вопрос в том:

У меня есть некоторый предопределенный код в Der1 . Почти все функции из Der2 делают то же самое. Как я могу написать это с меньшим количеством кода?

Я не могу добавить этот код к родительскому. Родительский класс трогать не следует.

Например, Der2.OwnFoo делает то же самое, что и Der1.OwnFoo , может быть, в python есть какая-то конструкция, позволяющая просто вызывать OwnFoo из первого класса и не писать этот код снова?


Я не могу изменить родительский элемент Der1 и Der2 ! Это должно быть Base .

Ответ №1:

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

 # Common code goes in this new class
class DerHelper:
    def __init__(self, parent):
        self._parent = parent
    def OwnFoo(self):
        print 'Do something 1', self._parent
    def OwnFoo2(self):
        print 'Do something 2', self._parent
    def Foo(self):
        print 'Do something 3', self._parent

# First derived class
class Der1(Base):
    def __init__(self):
        # include helper class by composition
        self._helper = DerHelper('Der1')
    def OwnFoo(self):
        self._helper.OwnFoo()
    def OwnFoo2(self):
        self._helper.OwnFoo2()
    def Foo(self):
        self._helper.Foo()

# Second derived class
class Der2(Base):
    def __init__(self):
        # include helper class by composition
        self._helper = DerHelper('Der2')
    def OwnFoo(self):
        self._helper.OwnFoo()
    def OwnFoo2(self):
        self._helper.OwnFoo2()
    def Foo(self):
        self._helper.Foo()
  

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

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

 d = Der1()
d.OwnFoo()
d.OwnFoo2()
d.Foo()

d = Der2()
d.OwnFoo()
d.OwnFoo2()
d.Foo()
  

Вывод:

 Do something 1 Der1
Do something 2 Der1
Do something 3 Der1
Do something 1 Der2
Do something 2 Der2
Do something 3 Der2
  

Ответ №2:

Создайте Der2 подкласс Der1 и готово.

 class Base:
   def Foo(self):
      pass

# First derived class
class Der1(Base):
   def OwnFoo(self):
      # Do something 1
   def OwnFoo2(self):
      # Do something 2

   def Foo(self):
      # Do something 3

# Second derived class (subclasses Der1)
class Der2(Der1):
   pass
  

Любое поведение внутри Der2 , на котором вы хотели бы специализироваться, может быть добавлено в определение класса. Если вы создадите новый метод с тем же именем в Der2 (например Der2.OwnFoo() ), то он перегрузит метод по умолчанию, который унаследован от Der1 .

РЕДАКТИРОВАТЬ: Если вы не можете изменить родительский элемент, перенесите все поведение, которое вы хотите унаследовать, в базовый класс, имея в виду, что вы можете перегрузить или настроить любой из методов в подклассах.

В коде:

 # Base class
class Base:
    def Foo1(self):
        # Do something 1
    def Foo2(self):
        # Do something 2
    def Foo(self):
        # Do something 3

# First derived class, inherits everything from Base
class Der1(Base):
    pass

# Second derived class
class Der2(Base):
    pass  
  

Существует «трюк», который вы можете сделать, чтобы вызвать исходный метод, унаследованный от родительского, зафиксировать возвращаемое значение, а затем настроить поведение. Это сработает только в том случае, если метод действительно возвращает значение, и может быть опасным, если метод манипулирует атрибутами внутри класса, если только вы этого не хотите и не ожидаете.

В коде:

 # Second derived class, with customized methods
class Der2(Base):
    # Anything that is not explicitly define is inherited from parent
    # as-is.

    def Foo(self):
        # My Foo() overloads Base.Foo() inherited from parent class. 
        # Do something "special" 3

    def Foo1(self):
        # Calls parent Base.Foo1() and then manipulates return data.
        base_output = Base.Foo1(self)
        # Do something "special" 1 with 'base_output'
  

Ответ №3:

Это домашнее задание?

Посмотрите на первую строку Der2 :

 class Der2(Base):
  

Что говорит о том, каков его родительский элемент (например, класс, с которого он происходит и от которого наследует методы и атрибуты)? Как вы могли бы это изменить?

Ответ №4:

Если Der1 и Der2 разделяют много кода, то вам следует поместить это в суперкласс; поскольку Base нельзя трогать, введите класс между ними:

 class Der(Base):
    def OwnFoo(self):
        ...

class Der1(Der):
    ...

class Der2(Der):
    ...
  

(В зависимости от вашей иерархии классов, параметр «производный Der2 от Der1 «, который рекомендуют другие, также может быть допустимым.)

Ответ №5:

Как насчет создания Der2 подкласса Der1 ?