我正在尝试找到包含方法代码的类的名称。
在我使用的下面的例子中 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()
在Python 3.x中,您可以简单地使用 __class__.__name__
。该 __class__
名字有点神奇,与此不一样 __class__
的属性 self
。
在Python 2.x中,没有很好的方法来获取该信息。您可以使用堆栈检查来获取代码对象,然后遍历类层次结构以寻找正确的方法,但它很慢且乏味,并且可能会在您不希望它时破坏。您还可以使用元类或类装饰器以某种方式对类进行后处理,但这两种方法都是相当具有侵入性的方法。你可以做一些非常丑陋的事情,比如访问 self.__nonexistant_attribute
,捕获AttributeError并从损坏的名称中提取类名。如果您只是想避免输入两次名称,那么这些方法都不值得;通过做类似的事情,至少忘记更新名称可以更加明显:
class C:
...
def report_name(self):
print C.__name__
inspect.getmro 按顺序为您提供方法可能来自的类的元组。一旦你发现其中一个在其中有方法名称 dict
, 你完成了:
for c in inspect.getmro(self.__class__):
if 'test' in vars(c): break
return c.__name__
使用 __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
你可以使用(滥用?) 私人名称 实现这个效果。如果你查找属性 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
你可以做
>>> 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
。这不是最漂亮的,但它确实有效。