0

Is it possible to append code to an existing class method without fully overwriting it?

Example:

class Test:

    def Do(self):
        print('initial')

And then add a print('new') to the Test.Do() method without overwriting the method fully. So something like:

def better_do(self):
    print('new') #Could also go at the end
    run_original_do(self)

test = Test()
test.Do() #This would then print new and initial

Reason: If I would update the third party library I want the possibly updated code to be updated and then I want my code to run before or after that new code. If I overwrite the entire method it means that I make that code static and any updates will not come through later unless I do the manual work of updating.

EDIT: One way of doing this I found is copying the original function and then using it in the newly defined one. This is taken from: https://stackoverflow.com/a/13503277/4532098 https://stackoverflow.com/a/6528148/4532098

import functools
import types

class Test:

    def initial(self, x):
        print(x)
        print('initial original')

def copy_func(func):
    new_func = types.FunctionType(func.__code__, func.__globals__, name=func.__name__,
                           argdefs=func.__defaults__,
                           closure=func.__closure__)
    new_func = functools.update_wrapper(new_func, func)
    new_func__kwdefaults__ = func.__kwdefaults__
    return new_func

z = copy_func(Test.initial)

def x(self, x):
    print('new!')
    z(self, x)

Test.initial = x

y = Test()
y.initial('xxx')

EDIT 2: Seeing it closed as duplicate, but the main thing here that I might not have stated clearly is that this is about a third party library. The answers in the "duplicate" post are all based on changing the code of the third party library, which I cannot. The overwritten class is used outside of my code as well so subclassing and putting in a decorator would not work, it does need to be the original class.

EDIT 3: No the duplication was sort of correct indeed, the nicest answer is in: https://stackoverflow.com/a/8726680/4532098 Not in the selected answer

Wealot
  • 201
  • 2
  • 9
  • Extend the class with your own class, override the method, use `super` to call the original…‽ – deceze Aug 15 '23 at 08:58
  • Point here is actually that the original class from a third party library is used in many parts of my code, but also the code of the third party library. So I want to really make sure the overwrite is done on the original class – Wealot Aug 15 '23 at 09:07
  • Added a possible solution, but I think maybe there is a better one where we don't go an copy functions in memory? – Wealot Aug 15 '23 at 09:10

1 Answers1

0

You can use inheritance and call your parent method:

class Test:
    def Do(self):
        print('initial')
        
class Test2(Test):
    def Do(self):
        print('new')
        super().Do()
        
Test().Do() #prints 'initial'
Test2().Do() #prints 'new' then prints 'initial'
Learning is a mess
  • 7,479
  • 7
  • 35
  • 71
  • Point here is actually that the original class from a third party library is used in many parts of my code, but also the code of the third party library. So I want to really make sure the overwrite is done on the original clas – Wealot Aug 15 '23 at 09:07
  • Seems like you're after a monkey patch then, you need to overwrite in that case (name the child class same as the first one) and replace imports everywhere to point to your local rewrite. – Learning is a mess Aug 15 '23 at 09:42
  • 1
    Yes something like that, eventually the best answer was in: https://stackoverflow.com/a/8726680/4532098 Although that question wasn't really the same as mine – Wealot Aug 15 '23 at 10:12