We can use method resolution order or mro() to find the name of SomeClass from some_method it has:
class SomeClass:
    def __init__(self):
        self.foo = 100
    
    def some_method(self):
        return self.foo
a = SomeClass()
print(a.some_method.__self__.__class__.mro()[0])
Outputs:
<class '__main__.SomeClass'>
that way we can find the name of the class that some_method belongs to even if it's inherited by SomeOtherClass:
class SomeClass:
    def __init__(self):
        self.foo = 100
    
    def some_method(self):
        return self.foo
class SomeOtherClass(SomeClass):
    def __init__(self):
        super().__init__()
        self.other_foo = 1
    
    def some_other_method(self):
        return self.other_foo
a = SomeOtherClass()
print([cls for cls in a.some_method.__self__.__class__.mro() if cls.__dict__.__contains__(a.some_method.__name__)][0])
print([cls for cls in a.some_other_method.__self__.__class__.mro() if cls.__dict__.__contains__(a.some_other_method.__name__)][0])
Outputs:
<class '__main__.SomeClass'>
<class '__main__.SomeOtherClass'>
or the names of all the classes that have some_method (or some_other_method):
print([cls for cls in a.some_method.__self__.__class__.mro() if hasattr(cls, a.some_method.__name__)])
print([cls for cls in a.some_other_method.__self__.__class__.mro() if hasattr(cls, a.some_other_method.__name__)])
Outputs:
[<class '__main__.SomeOtherClass'>, <class '__main__.SomeClass'>]
[<class '__main__.SomeOtherClass'>]
To get the __name__s in string:
print([cls.__name__ ...