В Python изменение унаследованного поведения без переписывания родительского класса - PullRequest
0 голосов
/ 07 мая 2019

В Python у меня есть класс ParentClass. Он определяет метод ParentClass.process (), среди других. ParentClass наследуется двумя дочерними классами: ChildA и ChildB. Это часть системы, которая выступает в роли колеса. Пользователь не должен иметь возможность изменять код пакета.

Во время выполнения система создает объекты ChildA и ChildB.

Теперь я хочу дать пользователю системы возможность изменять поведение метода .process () для объектов ChildA и ChildB.

Очевидно, что она может сделать это, переопределив ChildA.process () и ChildB.process (), но это будет копирование идентичного поведения дважды, и в целом это выглядит как очень странный подход.

Пользователь может унаследовать свой собственный класс от ParentClass и переопределить там .process (), но это означает, что мне нужно как-то динамически сообщить ChildA и ChildB, что наследовать.

Кроме того, все классы (ParentClass, ChildA и ChildB) имеют другие методы, кроме .process (), которые необходимо сохранить без изменений.

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

Ответы [ 2 ]

1 голос
/ 07 мая 2019

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

class ParentClass:
    def process(self):
        print("ParentClass.process() called from",type(self))

class ExtendedParent(ParentClass): 
    def process(self):
        super().process()
        print("Common Extension code for A and B",type(self))

class ChildA(ExtendedParent):
    pass

class ChildB(ExtendedParent):
    pass

a = ChildA()
b = ChildB()

a.process()
# ParentClass.process() called from <class '__main__.ChildA'>
# Common Extension code for A and B <class '__main__.ChildA'>

b.process()
# ParentClass.process() called from <class '__main__.ChildB'>
# Common Extension code for A and B <class '__main__.ChildB'>

Если ChildA и ChildB определены в вашем пакете и не имеют метода .process (),Вы могли бы поручить пользователю вашего пакета назначать методы этим классам напрямую, используя общую функцию, которой нет ни в одном классе:

def extendedProcess(self):
    ParentClass.process(self) # this replaces super().process()
    print("Common Extension code for A and B",type(self))

ChildA.process = extendedProcess        
ChildB.process = extendedProcess

Если у ChildA и / или ChildB есть переопределение process () и вашпользователь хочет изменить поведение process () в родительском классе, вот один из способов сделать это:

ParentClass_process = ParentClass.process
def extendedProcess(self):
    ParentClass_process(self) #call original code
    print("Common Extension code for A and B",type(self))    
ParentClass.process = extendedProcess  
1 голос
/ 07 мая 2019

Вы можете использовать метод класса для переназначения process для определенного класса

class ParentClass:
    def process(self):
        print("parent")
    @classmethod
    def reassign_process(cls, process):
        cls.process = process

class ChildA(ParentClass):
    def process(self):
        print("Child A")

class ChildB(ParentClass):
    def process(self):
        super().process()
        print("Child B")

p = ParentClass()
ca = ChildA()
cb = ChildB()

p.process()
# parent
ca.process()
# Child A
cb.process()
# parent
# Child B

def new_parent_process(self):
    print("New parent")

ParentClass.reassign_process(new_parent_process)

def new_childa_process(self):
    print("New child A")

ChildA.reassign_process(new_childa_process)

p.process()
# New parent
ca.process()
# New child A
cb.process()
# New parent
# Child B
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...