In Python, methods are just attributes that happen to be callable*. You'd have to hook in to attributes being set to see new methods being added to a class.
You'd have to use a metaclass to intercept new attributes being added to a class:
import types
class NewMethodAlerter(type):
def __setattr__(self, name, obj):
if isinstance(obj, types.FunctionType):
print(f'New method {name} added!')
super().__setattr__(name, obj)
class Demo(metaclass=NewMethodAlerter):
def existing_method(self):
pass
def new_method(self): pass
Demo.new_method = new_method
which then looks like this:
>>> class Demo(metaclass=NewMethodAlerter):
... def existing_method(self):
... pass
...
>>> def new_method(self): pass
>>> Demo.new_method = new_method
New method new_method added!
If you wanted to know about the initial set of attributes, the result of executing the class
body, then you have two options: use a metaclass, or in Python 3.6 and up, the __init_subclass__
method. Either one is called to create new classes, and can be used to inspect the attributes:
class InitialMethodAlerter(type):
def __new__(typ, name, bases, attrs):
for name, obj in attrs.items():
if isinstance(obj, types.FunctionType):
print(f'Method {name} defined!')
return super().__new__(typ, name, bases, attrs)
class Demo(metaclass=InitialMethodAlerter):
def existing_method(self):
pass
or the __init_subclass__
method:
class InitialMethodAlerter:
@classmethod
def __init_subclass__(cls, **kwargs):
for name, obj in vars(cls).items():
if isinstance(obj, types.FunctionType):
print(f'Method {name} defined!')
class Demo(InitialMethodAlerter):
def existing_method(self):
pass
You may want to read up on metaclasses at What is a metaclass in Python?
*Well, the attributes are functions actually. Functions are descriptor objects, which causes them to be bound when accessed via an instance. That binding process produces a method object, that when called takes the original function and passes in the instance to which it was bound.