Find the class in which the method is defined

I want to find out the type of class in which a particular method is defined (mainly covering the static scope of the method), from the method itself and without explicitly specifying it, for example

class SomeClass:
    def do_it(self):
        cls = enclosing_class() # <-- I need this.
        print(cls)

class DerivedClass(SomeClass):
    pass

obj = DerivedClass()
# I want this to print 'SomeClass'.
obj.do_it()

Is it possible?

+4
source share
6 answers

If you need it in Python 3.x, see my other answer - a closure cell __class__is all you need.


If you need to do this in CPython 2.6-2.7, RickyA's answer is close, but it does not work, because it relies on the fact that this method does not override any other method with the same name. Try adding a method Foo.do_itto your answer and it will print Foo, notSomeClass

, :

def do_it(self):
    mro = inspect.getmro(self.__class__)
    method_code = inspect.currentframe().f_code
    method_name = method_code.co_name
    for base in reversed(mro):
        try:
            if getattr(base, method_name).func_code is method_code:
                print(base.__name__)
                break
        except AttributeError:
            pass

( , AttributeError base, - do_it, base - do_it, , , , a func_code. , base , .)

Python 2.6+. Python , , , inspect.currentframe() None. , , , func_code None.

, 2.7+, 3.0+, func_code __code__, 2.x.


CPython 2.5 , inpsect CPython :

def do_it(self):
    mro = self.__class__.mro()
    method_code = sys._getframe().f_code
    method_name = method_code.co_name
    for base in reversed(mro):
        try:
            if getattr(base, method_name).func_code is method_code:
                print(base.__name__)
                break
        except AttributeError:
            pass

, mro() ; ( ...), mro, ... 2.6 inspect .

Python 2.x, , CPython... PyPy. inspect , , frame code , CPython, inspect, sys._getframe ...

+4

-, , , , , ...

, , , Python 3.0+. ( 2.x, . .)

, Python 3.x super -. super() super(THISCLASS, self), THISCLASS , ? *

super, ... PEP 3135 , :

__class__, , .

Python, Python 3.x -... 3.2+ __class__ , :

, super(). __class__ - , , __class__ super. super() , , , , , .

(, , , CPython 3.0-3.5 PyPy3 2.0-2.1 super .)

In [1]: class C:
   ...:     def f(self):
   ...:         print(__class__)
In [2]: class D(C):
   ...:     pass
In [3]: D().f()
<class '__main__.C'>

, , , , -, , . ; , __class__.__name__ __class__.__qualname__ ( ) .


* : , - Python. , , - super ...

+2

@abarnert, .

hardcore ( python2.7):

import inspect
from http://stackoverflow.com/a/22898743/2096752 import getMethodClass

def enclosing_class():
    frame = inspect.currentframe().f_back
    caller_self = frame.f_locals['self']
    caller_method_name = frame.f_code.co_name
    return getMethodClass(caller_self.__class__, caller_method_name)

class SomeClass:
    def do_it(self):
        print(enclosing_class())

class DerivedClass(SomeClass):
    pass

DerivedClass().do_it() # prints 'SomeClass'

, , :

  • /staticmethod/classmethod
  • self ( @abarnert, , frame.f_code.co_varnames[0])
+1

, @mgilson, .

class SomeClass:
    pass

class DerivedClass(SomeClass):
    pass

SomeClass DerivedClass.
__class__.name__, , .

do_it(), DerivedClass self, , , DerivedClass.

:

class SomeClass:
    pass

class DerivedClass(SomeClass):
    def do_it(self):
        for base in self.__class__.__bases__:
            print base.__name__
obj = DerivedClass()
obj.do_it() # Prints SomeClass

Edit:
, , , .

class SomeClass:
    def do_it(self):
        cls = self.__class__.__bases__[0].__name__
        print cls

class DerivedClass(SomeClass):
    pass

obj = DerivedClass()
obj.do_it() # prints SomeClass
0

[] :

import inspect

class Foo:
    pass

class SomeClass(Foo):
    def do_it(self):
        mro = inspect.getmro(self.__class__)
        method_name = inspect.currentframe().f_code.co_name
        for base in reversed(mro):
            if hasattr(base, method_name):
                print(base.__name__)
                break

class DerivedClass(SomeClass):
    pass

class DerivedClass2(DerivedClass):
    pass

DerivedClass().do_it()
>> 'SomeClass'

DerivedClass2().do_it()
>> 'SomeClass'

SomeClass().do_it()
>> 'SomeClass'

, - "do_it", mro.

0

, , , , , :

, , (, " , ClassA.x() , ClassB.y() ).

- . , , .

, . , , super() super (ClassX, self).

" ", , , . , , , , ( ), ( ), . (, , .)

, :

import collections
import functools
import inspect

_calls = {}
def inject(cls):
    cls._calls = collections.Counter()
    _calls[cls.__name__] = cls._calls
    for name, method in cls.__dict__.items():
        if inspect.isfunction(method):
            @functools.wraps(method)
            def wrapper(*args, **kwargs):
                cls._calls[name] += 1
                return method(*args, **kwargs)
            setattr(cls, name, wrapper)
    return cls

@inject
class A(object):
    def f(self):
        print('A.f here')

@inject
class B(A):
    def f(self):
        print('B.f here')

@inject
class C(B):
    pass

@inject
class D(C):
    def f(self):
        print('D.f here')

d = D()
d.f()
B.f(d)

print(_calls)

:

{'A': Counter(), 
 'C': Counter(), 
 'B': Counter({'f': 1}), 
 'D': Counter({'f': 1})}

, , ?

0

All Articles