#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
?