我正在尝试查找包含方法代码的类的名称。
在下面的示例中,我使用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()
答案 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
的基类。它不是最漂亮的,但它确实有效。