简体   繁体   中英

Python, how to alter a method of another class' instance

I would like to add some small functionality to a method of another class' instance. What I tried is listed below. With the same approach it's possible to completely change the method. But I would like to keep a slightly altered version of the original method. Is that possible?

BTW: The classes can not inherit from one another, because I don't necessarily know what class B is.

class A:
    def alter_fn(self, obj):
        def wrapper():
            func = getattr(obj, obj.fn_name)
            out = func()
            print('out = ', out)
            return out
        setattr(obj, obj.fn_name, wrapper)
        return

class B:
    def __init__(self) -> None:
        self.fn_name = 'fn'

    def fn(self):
        return 123


a=A()
b=B()

a.alter_fn(b)
b.fn()

For obvious reasons this raises a recursion depth error but I do not know how to avoid that. I also tried func = copy(getattr(obj, obj.fn_name))

After altering the method b.fn I would like it to return the value, the unaltered function would return (here 123) but I would also like it to do something else with this output, in this example print it.

Move the assignment of func above the definition of wrapper .

...
def alter_fn(self, obj):
    func = getattr(obj, obj.fn_name)
    def wrapper():
        ...

This way getattr is called only once and wrapper can access func as a closure variable.

You just need to take the func = getattr(obj, obj.fn_name) out of the wrapper function.

class A:
    def alter_fn(self, obj):
        func = getattr(obj, obj.fn_name)
        def wrapper():
            out = func()
            print('out = ', out)
            return out
        setattr(obj, obj.fn_name, wrapper)
        return

You need to get the wrapped function before re-assigning it:

def alter_fn(self, obj):
    func = getattr(obj, obj.fn_name)
    def wrapper():
        out = func()
        print('out = ', out)
        return out
    setattr(obj, obj.fn_name, wrapper)
    return

This way func is assigned only once, when the original function is called. Thus, you can safely call it without calling wrapper() again by accident.

Also consider using functools.wraps() to keep the docstring and name information of the string the same.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM