包含方法代码的类的名称

时间:2010-05-06 14:12:07

标签: python introspection

我正在尝试查找包含方法代码的类的名称。

在下面的示例中,我使用self.__class__.__name__,但当然这会返回self为实例的类的名称,而不是包含test()方法代码的类。 b.test()会打印'B',而我希望获得'A'

我查看了inspect模块文档,但没有发现任何直接有用的内容。

class A:
  def __init__(self):
    pass
  def test(self):
    print self.__class__.__name__

class B(A):
  def __init__(self):
    A.__init__(self)



a = A()
b = B()

a.test()
b.test()

5 个答案:

答案 0 :(得分:7)

在Python 3.x中,您只需使用__class__.__name__即可。 __class__名称有点神奇,与__class__的{​​{1}}属性不同。

在Python 2.x中,没有好的方法来获取这些信息。您可以使用堆栈检查来获取代码对象,然后遍历类层次结构以查找正确的方法,但它很慢且乏味,并且可能会在您不希望它时破坏。您还可以使用元类或类装饰器以某种方式对类进行后处理,但这两种方法都是相当具有侵入性的方法。你可以做一些非常丑陋的事情,比如访问self,捕获AttributeError并从错位名称中提取类名。如果您只是想避免输入两次名称,那么这些方法都不值得。通过执行以下操作,至少忘记更新名称可以更加明显:

self.__nonexistant_attribute

答案 1 :(得分:4)

inspect.getmro按顺序为您提供方法可能来自的类的元组。一旦你找到其中一个在dict中有方法名称的人,你就完成了:

for c in inspect.getmro(self.__class__):
    if 'test' in vars(c): break
return c.__name__

答案 2 :(得分:2)

使用类对象本身的__dict__

class A(object):
    def foo(self):
        pass

class B(A):
    pass

def find_decl_class(cls, method):
    if method in cls.__dict__:
        return cls
    for b in cls.__bases__:
        decl = find_decl_class(b, method)
        if decl:
            return decl

print 'foo' in A.__dict__
print 'foo' in B.__dict__
print find_decl_class(B, 'foo').__name__

将打印为True,False,A

答案 3 :(得分:2)

您可以使用(滥用?)private name mangling来实现此效果。如果您在方法内查找self上以__开头的属性,则python会将名称从__attribute更改为_classThisMethodWasDefinedIn__attribute

只是以某种方式将您想要的类名存储在mangled-form中,方法可以看到它。作为一个例子,我们可以在基类上定义一个__new__方法:

def mangle(cls, attrname):
    if not attrname.startswith('__'):
        raise ValueError('attrname must start with __')
    return '_%s%s' % (cls.__name__, attrname)

class A(object):

    def __new__(cls, *args, **kwargs):
        obj = object.__new__(cls)
        for c in cls.mro():
            setattr(obj, mangle(c, '__defn_classname'), c.__name__)
        return obj

    def __init__(self):
        pass

    def test(self):
        print self.__defn_classname

class B(A):

    def __init__(self):
        A.__init__(self)



a = A()
b = B()

a.test()
b.test()

打印:

A
A

答案 4 :(得分:0)

你可以做到

>>> class A(object):
...   def __init__(self):
...     pass
...   def test(self):
...     for b in self.__class__.__bases__:
...       if hasattr(b, 'test'):
...         return b.__name__
...     return self.__class__.__name__
... 
>>> class B(A):
...   def __init__(self):
...     A.__init__(self)
...
>>> B().test()
'A'
>>> A().test()
'A'
>>> 

请记住,您可以使用__class__.__base__来简化它,但如果您使用多重继承,则此版本将更好用。

它只是首先检查其test的基类。它不是最漂亮的,但它确实有效。