Как вызвать исходный метод, когда он очищен от обезьяны?

У меня есть класс в основном проекте, который я не хочу менять.

class A(): def __init__(self, firstname, lastname): self.firstname = firstname self.lastname = lastname def name(self): # this method could be much more complex return self.lastname.upper() 

Я пытаюсь создать плагин mechansim. Пока что так хорошо, у меня есть точка расширения следующим образом:

 if __name__ == '__main__': ''' The main project has an extension point that allows me to do''' # for each class extension such as AExtended: A.name = AExtended.name ''' After the extensions are loaded, some behaviours may be changed''' a = A("John", "Doe") print(a.name()) 

Плагин можно записать следующим образом:

 class AExtended(A): ''' This is an extension I provide through a plugin mechanism ''' def name(self): return self.firstname + ' ' + self.lastname.upper() 

Все это работает очень хорошо. Теперь я получаю «John DOE».

Моя проблема в том, что исходный метод name() может быть довольно сложным. Другими словами, я не могу позволить себе называть self.lastname.upper() в AExtended . Я бы назвал метод «супер», который больше не существует, потому что он был перезаписан.

Как я могу изменить свой код, чтобы добиться чего-то вроде этого:

 class AExtended(A): def name(self): # I'm looking for a way to call the base implementation that was in A.name() return self.firstname + ' ' + parent.name() 

Спасибо за вашу помощь!

Изменить: некоторые объяснения того, что я пытаюсь сделать.

  • Я хочу, чтобы плагин исправлял поведение A Я не могу позволить себе менять существующих потребителей A
  • Есть много классов, таких как A которые можно изменить, я бы хотел, чтобы плагины имели полный контроль и ответственность
  • Это правда, что AExtended не нужно наследовать от A , но это был простой способ получить доступ к self.firstname . У меня нет проблем, следуя другому шаблону дизайна, если он может помочь.

У меня есть обходное решение, но это не очень элегантно и сложно обобщить

 class AExtended(A): def name(self): # I'm looking for a way to call the base implementation that was in A.name() return self.firstname + ' ' + self.parentname() #in main A.parentname = A.name A.name = AExtended.name 

4 Solutions collect form web for “Как вызвать исходный метод, когда он очищен от обезьяны?”

Вот полный пример того, что я намекал. Не стесняйтесь кричать на меня, и я могу объединить свои ответы или сжать ни одного или что-то еще, просто проще предоставить альтернативу в качестве нового ответа. Я позволю коду говорить, вместо того, чтобы плохо объяснять это. 🙂

 ## Some shared class that is used all over the place and needs to be patched. class A(object): def __init__(self): self.firstname = 'Bob' # Print my first name. def name(self): return self.firstname # Use this to allow patching arbitrary methods... @classmethod def patch(cls, func_name): def patch_by_name(new_func): old_func = getattr(cls, func_name) def patched_func(self): return new_func(self, old_func) setattr(cls, func_name, patched_func) return patch_by_name ## Some other area of the code where you want to throw in a patch class PatchedA(A): # doesn't need to subclass, but comes in handy sometimes @A.patch('name') def name(self, orig_func): return 'I am ' + orig_func(self) + 'McWizwaz' print 'Who are you, A class?' print A().name() # prints 'I am Bob McWizwaz' 

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

 def name_decorator(method): def decorate_name(self=None): return stuff + method(self) return decorate_name A.name = name_decorator(A.name) 

Позже вызов A.name вызовет decorate_name с self поскольку текущий экземпляр и method будут доступны ему, что указывает на функцию во время переназначения.

 class ABase(object): def name(self): pass class A(object): pass class AExtension(ABase): def name(self): return ABase.name(self) A.name = AExtension.name 

Одним из вариантов, который не всегда может быть лучшим на языке Python, является использование декоратора @override из этого нестандартного пакета . Но это жизнеспособный вариант, только если ваши две функции работают на разные типы или различное количество аргументов. Помимо этого, вы не можете многое сделать, помимо переименования вашей функции.

  • Python 3 - Zip - это итератор в кадре данных pandas
  • IndexError: индекс индекса вне диапазона - файл CSV
  • Операция строки python expandtabs
  • Оператор Modulo в Python
  • filedialog, tkinter и открывающие файлы
  • Тип генератора подсказок в python 3.6
  • Python: относительный импорт означает, что вы не можете самостоятельно выполнить подпакет?
  • управлять ошибками в python
  • Python - лучший язык программирования в мире.