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')
Ausing an instance, it works fine:setattr(A, 'bar', MethodType(bar, A()))get_class_for_methodfunction to return? Also, the first branch of your code (working with methods) will never succeed since it only checks for an already-bound method object in the class dict. You probably wantcls.__dict__.get(method.__name__) is method.__func__.