I have the following code (python 3):
import inspect
def get_class_for_method(method):
    if inspect.ismethod(method):
        for cls in inspect.getmro(method.__self__.__class__):
            if cls.__dict__.get(method.__name__) is method:
                return cls
        method = method.__func__  # fallback to __qualname__ parsing
    if inspect.isfunction(method):
        cls = getattr(inspect.getmodule(method),
                      method.__qualname__.split('.<locals>', 1)[0].rsplit('.', 1)[0])
        if isinstance(cls, type):
            return cls
    return None
class A:
    def __init__(self):
        self.name = 'Class A'
    def foo(self):
        print('foo: ' + self.name)
def bar(self):
    print('bar: ' + self.name)
setattr(A, bar.__name__, bar)
instance_of_a = A()
instance_of_a.foo()
instance_of_a.bar()
print(get_class_for_method(A.foo))
print(get_class_for_method(A.bar))
And get the following output:
foo: Class A
bar: Class A
<class '__main__.A'>
None
So the methods are working like expected. The only thing what I'm not able to do is to bind the method to the object. So that print(get_class_for_method(A.bar)) will return <class '__main__.A'> instead of None.
types.MethodType of the types module looks like exactly what I need but it works only on an explicit instances of the class. What I figured out so far is that I have to set the __self__ attribute of the method, but if I'm trying that seems not to change anything.
Edit: Additional information.
The idea behind my question is to write a decorator method to overwrite (monkey patch) class methods. The following code is the one I have for now. It works for overwriting methods like expected, but if a method was added dynamically, it fails because get_class_for_method (grabbed from Get defining class of unbound method object in Python 3) return None.
def patch_method(original_fnc):
    def get_class_for_method(method):
        if inspect.ismethod(method):
            for cls in inspect.getmro(method.__self__.__class__):
                if cls.__dict__.get(method.__name__) is method:
                    return cls
            method = method.__func__  # fallback to __qualname__ parsing
        if inspect.isfunction(method):
            cls = getattr(inspect.getmodule(method),
                          method.__qualname__.split('.<locals>', 1)[0].rsplit('.', 1)[0])
            if isinstance(cls, type):
                return cls
        return None
    def wrap(fnc):
        fnc_object = get_class_for_method(original_fnc)
        if fnc_object is not None:
            if fnc.__doc__ is None:
                fnc.__doc__ = original_fnc.__doc__
            method = partial(fnc, original_fnc)
            method.__doc__ = fnc.__doc__
            setattr(fnc_object, original_fnc.__name__, method)
        return None
    return wrap
Usage of the decorator:
@patch_method(module.Object.method)
def patched_method(original, self, arg):
    print('foo')
    original(self, arg)
    print('bar')
 
     
     
    