我发现了以下函数,但我不知道为什么需要额外的__bases__
扫描:
def getMembersWithBases(classType):
members = set(dir(classType))
# recursive bases scan
for baseClassType in classType.__bases__:
members.update(getMembersWithBases(baseClassType))
return members
以下函数速度更快,并且给出相同的结果 - 那么为什么还需要额外的 __bases__
扫描?
def getMembers(classType):
members = set(dir(classType))
return members
一些包含新式和旧式类的测试代码:
class Father(object):
def testFather():
pass
class Mother(object):
def testMother():
pass
class Child(Father, Mother):
def testChild():
pass
print type(Child)
print getMembers(Child) == getMembersWithBases(Child)
class Father:
def testFather():
pass
class Mother:
def testMother():
pass
class Child(Father, Mother):
def testChild():
pass
print type(Child)
print getMembers(Child) == getMembersWithBases(Child)
结果:
<type 'type'>
True
<type 'classobj'>
True
最佳答案
确实,dir()
function对于类,已经包含 __bases__
中列出的所有类:
If the object is a type or class object, the list contains the names of its attributes, and recursively of the attributes of its bases.
但是,类可以通过指定 __dir__
方法来覆盖该行为(通过元类,类方法是不够的):
If the object has a method named
__dir__()
, this method will be called and must return the list of attributes.
当存在 __dir__()
方法时,__bases__
不会递归:
>>> class Foo(object):
... def spam(self): pass
...
>>> class Bar(object):
... def ham(self): pass
...
>>> class CustomDirMetaclass(type):
... def __dir__(cls):
... return ['eggs']
...
>>> class Baz(Foo, Bar):
... __metaclass__ = CustomDirMetaclass
... def eggs(self): pass
...
>>> dir(Baz)
['eggs']
>>> getMembers(Baz)
set(['eggs'])
>>> getMembersWithBases(Baz)
set(['__module__', '__getattribute__', 'eggs', '__reduce__', '__subclasshook__', '__dict__', '__sizeof__', '__weakref__', '__init__', 'ham', '__setattr__', '__reduce_ex__', '__new__', 'spam', '__format__', '__class__', '__doc__', '__delattr__', '__repr__', '__hash__', '__str__'])
因此,getMembersWithBases()
类方法中对 __bases__
的显式递归可能是试图绕过任何自定义 __dir__()
实现.
否则,__bases__
上的递归是完全多余的。
在我个人看来,即使if有__dir__()
方法,__bases__
上的递归也是多余的存在于类层次结构中。在这种情况下,__dir__()
方法重写是错误的,因为 方法应该递归 __bases__
中列出的类以正确模仿行为dir()
函数。
说实话,我怀疑您找到的函数的作者不知道 dir()
的递归性质,并且添加了 __bases__
递归针,而不是作为绕过自定义 __dir__()
方法的手段。
关于Python 类成员扫描 - 为什么在获取成员时需要 __bases__ 递归扫描?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13154226/